Full Code of gin-gonic/gin for AI

master d3ffc9985281 cached
130 files
840.2 KB
247.7k tokens
1590 symbols
3 requests
Download .txt
Showing preview only (880K chars total). Download the full file or copy to clipboard to get everything.
Repository: gin-gonic/gin
Branch: master
Commit: d3ffc9985281
Files: 130
Total size: 840.2 KB

Directory structure:
gitextract_g5woqams/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.yaml
│   │   ├── config.yml
│   │   └── feature-request.yaml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── codeql.yml
│       ├── gin.yml
│       ├── goreleaser.yml
│       └── trivy-scan.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yaml
├── BENCHMARKS.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── auth.go
├── auth_test.go
├── benchmarks_test.go
├── binding/
│   ├── binding.go
│   ├── binding_msgpack_test.go
│   ├── binding_nomsgpack.go
│   ├── binding_test.go
│   ├── bson.go
│   ├── default_validator.go
│   ├── default_validator_benchmark_test.go
│   ├── default_validator_test.go
│   ├── form.go
│   ├── form_mapping.go
│   ├── form_mapping_benchmark_test.go
│   ├── form_mapping_test.go
│   ├── header.go
│   ├── json.go
│   ├── json_test.go
│   ├── msgpack.go
│   ├── msgpack_test.go
│   ├── multipart_form_mapping.go
│   ├── multipart_form_mapping_test.go
│   ├── plain.go
│   ├── protobuf.go
│   ├── query.go
│   ├── toml.go
│   ├── toml_test.go
│   ├── uri.go
│   ├── validate_test.go
│   ├── xml.go
│   ├── xml_test.go
│   ├── yaml.go
│   └── yaml_test.go
├── codec/
│   └── json/
│       ├── api.go
│       ├── go_json.go
│       ├── json.go
│       ├── jsoniter.go
│       └── sonic.go
├── codecov.yml
├── context.go
├── context_appengine.go
├── context_file_test.go
├── context_test.go
├── debug.go
├── debug_test.go
├── deprecated.go
├── deprecated_test.go
├── doc.go
├── docs/
│   └── doc.md
├── errors.go
├── errors_test.go
├── examples/
│   └── README.md
├── fs.go
├── fs_test.go
├── gin.go
├── ginS/
│   ├── README.md
│   ├── gins.go
│   └── gins_test.go
├── gin_integration_test.go
├── gin_test.go
├── githubapi_test.go
├── go.mod
├── go.sum
├── internal/
│   ├── bytesconv/
│   │   ├── bytesconv.go
│   │   └── bytesconv_test.go
│   └── fs/
│       ├── fs.go
│       └── fs_test.go
├── logger.go
├── logger_test.go
├── middleware_test.go
├── mode.go
├── mode_test.go
├── path.go
├── path_test.go
├── recovery.go
├── recovery_test.go
├── render/
│   ├── bson.go
│   ├── data.go
│   ├── html.go
│   ├── json.go
│   ├── msgpack.go
│   ├── pdf.go
│   ├── protobuf.go
│   ├── reader.go
│   ├── reader_test.go
│   ├── redirect.go
│   ├── render.go
│   ├── render_msgpack_test.go
│   ├── render_test.go
│   ├── text.go
│   ├── toml.go
│   ├── xml.go
│   └── yaml.go
├── response_writer.go
├── response_writer_test.go
├── routergroup.go
├── routergroup_test.go
├── routes_test.go
├── test_helpers.go
├── testdata/
│   ├── certificate/
│   │   ├── cert.pem
│   │   └── key.pem
│   ├── protoexample/
│   │   ├── test.pb.go
│   │   └── test.proto
│   ├── template/
│   │   ├── hello.tmpl
│   │   └── raw.tmpl
│   └── test_file.txt
├── tree.go
├── tree_test.go
├── utils.go
├── utils_test.go
└── version.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yaml
================================================
name: Bug Report
description: Found something you weren't expecting? Report it here!
labels: ["type/bug"]
body:
  - type: markdown
    attributes:
      value: |
        NOTE: If your issue is a security concern, please send an email to appleboy.tw@gmail.com instead of opening a public issue.
  - type: markdown
    attributes:
      value: |
        1. Please speak English, this is the language all maintainers can speak and write.
        2. Please ask questions problems on our Discussions Forum (https://github.com/gin-gonic/gin/discussions).
        3. Make sure you are using the latest release and
           take a moment to check that your issue hasn't been reported before.
  - type: textarea
    id: description
    attributes:
      label: Description
      description: |
        Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below)
  - type: input
    id: gin-ver
    attributes:
      label: Gin Version
      description: Gin version (or commit reference) of your instance
    validations:
      required: true
  - type: dropdown
    id: can-reproduce
    attributes:
      label: Can you reproduce the bug?
      description: |
        If so, please write the steps to reproduce the bug.
      options:
        - "Yes"
        - "No"
    validations:
      required: true
  - type: markdown
    attributes:
      value: |
        It's really important to provide pertinent logs
        Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help
        In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
  - type: textarea
    id: source-code
    attributes:
      label: Source Code
      description: If this issue involves source code, please provide a minimal reproducible example
  - type: input
    id: go-ver
    attributes:
      label: Go Version
      description: The version of Go running on the server
  - type: input
    id: os-ver
    attributes:
      label: Operating System
      description: The operating system you are using to run Gin


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: Go.dev API Documentation
    url: https://pkg.go.dev/github.com/gin-gonic/gin
    about: Comprehensive API documentation for Gin.
  - name: Gin User Guides
    url: https://gin-gonic.com/
    about: In-depth user guides and tutorials for using Gin.
  - name: Discussions Forum
    url: https://github.com/gin-gonic/gin/discussions
    about: Questions and configuration or deployment problems can also be discussed.


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yaml
================================================
name: Feature Request
description: Got an idea for a feature that Gin doesn't have currently?  Submit your idea here!
labels: ["type/proposal"]
body:
  - type: markdown
    attributes:
      value: |
        1. Please speak English, this is the language all maintainers can speak and write.
        2. Please ask questions problems on our Discussions Forum (https://github.com/gin-gonic/gin/discussions).
        3. Please take a moment to check that your feature hasn't already been suggested.
  - type: textarea
    id: description
    attributes:
      label: Feature Description
      placeholder: |
        I think it would be great if Gin had...
    validations:
      required: true


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
# Pull Request Checklist

Please ensure your pull request meets the following requirements:

- [ ] Open your pull request against the `master` branch.
- [ ] All tests pass in available continuous integration systems (e.g., GitHub Actions).
- [ ] Tests are added or modified as needed to cover code changes.
- [ ] If the pull request introduces a new feature, the feature is documented in the `docs/doc.md`.

Thank you for contributing!


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: gomod
    directory: /
    schedule:
      interval: daily
  - package-ecosystem: github-actions
    directory: /
    groups:
      actions:
        patterns:
          - "*"
    schedule:
      interval: daily


================================================
FILE: .github/workflows/codeql.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"

on:
  push:
    branches: [master]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [master]
  schedule:
    - cron: "0 17 * * 5"

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest

    permissions:
      # required for all workflows
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        # Override automatic language detection by changing the below list
        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
        # TODO: Enable for javascript later
        language: ["go"]

    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      # Initializes the CodeQL tools for scanning.
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v4
        with:
          languages: ${{ matrix.language }}
          # If you wish to specify custom queries, you can do so here or in a config file.
          # By default, queries listed here will override any specified in a config file.
          # Prefix the list here with "+" to use these queries and those in the config file.
          # queries: ./path/to/local/query, your-org/your-repo/queries@main

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v4


================================================
FILE: .github/workflows/gin.yml
================================================
name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

permissions:
  contents: read

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: Set up Go
        uses: actions/setup-go@v6
        with:
          go-version: "^1"
      - name: Setup golangci-lint
        uses: golangci/golangci-lint-action@v9
        with:
          version: v2.11
          args: --verbose
  test:
    needs: lint
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
        go: ["1.25", "1.26"]
        test-tags:
          [
            "",
            "-tags nomsgpack",
            '--ldflags="-checklinkname=0" -tags sonic',
            "-tags go_json",
            "-race",
          ]
        include:
          - os: ubuntu-latest
            go-build: ~/.cache/go-build
          - os: macos-latest
            go-build: ~/Library/Caches/go-build
    name: ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }}
    runs-on: ${{ matrix.os }}
    env:
      GO111MODULE: on
      TESTTAGS: ${{ matrix.test-tags }}
      GOPROXY: https://proxy.golang.org
    steps:
      - name: Set up Go ${{ matrix.go }}
        uses: actions/setup-go@v6
        with:
          go-version: ${{ matrix.go }}
          cache: false

      - name: Checkout Code
        uses: actions/checkout@v6
        with:
          ref: ${{ github.ref }}

      - uses: actions/cache@v5
        with:
          path: |
            ${{ matrix.go-build }}
            ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-go-

      - name: Run Tests
        run: make test

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v5
        with:
          flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}


================================================
FILE: .github/workflows/goreleaser.yml
================================================
name: Goreleaser

on:
  push:
    tags:
      - "*"

permissions:
  contents: write

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: Set up Go
        uses: actions/setup-go@v6
        with:
          go-version: "^1"
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v7
        with:
          # either 'goreleaser' (default) or 'goreleaser-pro'
          distribution: goreleaser
          version: latest
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Trigger Go module reindex (pkg.go.dev)
        run: |
          echo "Triggering Go module reindex at proxy.golang.org"
          curl -sSf "https://proxy.golang.org/github.com/${GITHUB_REPOSITORY,,}/@v/${GITHUB_REF_NAME}.info"


================================================
FILE: .github/workflows/trivy-scan.yml
================================================
name: Trivy Security Scan

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  schedule:
    # Run daily at 00:00 UTC
    - cron: "0 0 * * *"
  workflow_dispatch: # Allow manual trigger

permissions:
  contents: read
  security-events: write # Required for uploading SARIF results

jobs:
  trivy-scan:
    name: Trivy Security Scan
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Run Trivy vulnerability scanner (source code)
        uses: aquasecurity/trivy-action@0.35.0
        with:
          scan-type: "fs"
          scan-ref: "."
          scanners: "vuln,secret,misconfig"
          format: "sarif"
          output: "trivy-results.sarif"
          severity: "CRITICAL,HIGH,MEDIUM"
          ignore-unfixed: true

      - name: Upload Trivy results to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v4
        if: always()
        with:
          sarif_file: "trivy-results.sarif"

      - name: Run Trivy scanner (table output for logs)
        uses: aquasecurity/trivy-action@0.35.0
        if: always()
        with:
          scan-type: "fs"
          scan-ref: "."
          scanners: "vuln,secret,misconfig"
          format: "table"
          severity: "CRITICAL,HIGH,MEDIUM"
          ignore-unfixed: true
          exit-code: "1"


================================================
FILE: .gitignore
================================================
vendor/*
!vendor/vendor.json
coverage.out
count.out
test
profile.out
tmp.out

# Develop tools
.idea/
.vscode/


================================================
FILE: .golangci.yml
================================================
version: "2"
linters:
  enable:
    - asciicheck
    - copyloopvar
    - dogsled
    - durationcheck
    - errorlint
    - gosec
    - misspell
    - nakedret
    - nilerr
    - nolintlint
    - perfsprint
    - revive
    - testifylint
    - usestdlibvars
    - wastedassign
  settings:
    gosec:
      excludes:
        - G115
    perfsprint:
      int-conversion: true
      err-error: true
      errorf: true
      sprintf1: true
      strconcat: true
    testifylint:
      enable-all: true
  exclusions:
    generated: lax
    presets:
      - comments
      - common-false-positives
      - legacy
      - std-error-handling
    rules:
      - linters:
          - structcheck
          - unused
        text: '`data` is unused'
      - linters:
          - staticcheck
        text: 'SA1019:'
      - linters:
          - revive
        text: 'var-naming:'
      - linters:
          - revive
        text: 'exported:'
      - linters:
          - gosec
        path: _test\.go
      - linters:
          - revive
        path: _test\.go
    paths:
      - third_party$
      - builtin$
      - examples$
formatters:
  enable:
    - gofmt
    - gofumpt
    - goimports
  settings:
    gofmt:
      rewrite-rules:
        - pattern: 'interface{}'
          replacement: 'any'
  exclusions:
    generated: lax
    paths:
      - gin.go


================================================
FILE: .goreleaser.yaml
================================================
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.
  disable: 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: github

  # 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: "Refactor"
      regexp: "^.*refactor[(\\w)]*:+.*$"
      order: 3
    - title: "Build process updates"
      regexp: ^.*?(build|ci)(\(.+\))??!?:.+$
      order: 4
    - title: "Documentation updates"
      regexp: ^.*?docs?(\(.+\))??!?:.+$
      order: 4
    - title: Others
      order: 999


================================================
FILE: BENCHMARKS.md
================================================
# Gin Benchmark Report

**Machine:** Apple M4 Pro
**OS:** macOS (Darwin 25.3.0), arm64
**Date:** March 15th, 2026
**Gin Version:** v1.12.0
**Go Version:** 1.25.8 darwin/arm64
**Source:** [Go HTTP Router Benchmark](https://github.com/gin-gonic/go-http-routing-benchmark)

---

## Table of Contents

- [Summary](#summary)
- [Memory Consumption](#memory-consumption)
- [Benchmark Results](#benchmark-results)
  - [GitHub API (203 routes)](#github-api-203-routes)
  - [Google+ API (13 routes)](#google-api-13-routes)
  - [Parse API (26 routes)](#parse-api-26-routes)
  - [Static Routes (157 routes)](#static-routes-157-routes)
- [Micro Benchmarks](#micro-benchmarks)
  - [Single Param](#single-param)
  - [5 Params](#5-params)
  - [20 Params](#20-params)
  - [Param Write](#param-write)

---

## Summary

The table below ranks all routers by **GitHub API throughput** (203 routes, all methods), which best represents real-world routing workloads. _Lower ns/op is better._

| Rank | Router        |     ns/op |      B/op | allocs/op |     Zero-alloc     |
| :--: | :------------ | --------: | --------: | --------: | :----------------: |
|  1   | **Gin**       |     9,944 |         0 |         0 | :white_check_mark: |
|  2   | **BunRouter** |    10,281 |         0 |         0 | :white_check_mark: |
|  3   | **Echo**      |    11,072 |         0 |         0 | :white_check_mark: |
|  4   | HttpRouter    |    15,059 |    13,792 |       167 |                    |
|  5   | HttpTreeMux   |    49,302 |    65,856 |       671 |                    |
|  6   | Chi           |    94,376 |   130,817 |       740 |                    |
|  7   | Beego         |   101,941 |    71,456 |       609 |                    |
|  8   | Fiber         |   109,148 |         0 |         0 | :white_check_mark: |
|  9   | Macaron       |   121,785 |   147,784 |     1,624 |                    |
|  10  | Goji v2       |   242,849 |   313,744 |     3,712 |                    |
|  11  | GoRestful     |   885,678 | 1,006,744 |     3,009 |                    |
|  12  | GorillaMux    | 1,316,844 |   225,667 |     1,588 |                    |

**Key takeaways:**

- **Gin**, **BunRouter**, and **Echo** form the top tier — all achieve zero heap allocations and route the full GitHub API in ~10 us.
- **HttpRouter** remains extremely fast but incurs 1 alloc per parameterized route (167 allocs for 203 routes).
- **Fiber** also achieves zero allocations, but its fasthttp-based benchmark infrastructure adds per-iteration reset overhead — do not compare its absolute ns/op directly with net/http routers.
- **GorillaMux** and **GoRestful** are feature-rich but orders of magnitude slower, making them less suitable for latency-sensitive applications.

> **Fiber caveat:** Fiber benchmarks use `fasthttp.RequestCtx` with per-iteration Reset, which adds constant overhead not present in net/http benchmarks. Fiber-vs-Fiber comparisons are valid; cross-framework comparisons should be interpreted with care.

---

## Memory Consumption

Memory required for loading the routing structure (lower is better). Sorted by bytes ascending.

### Static Routes: 157

| Router         |      Bytes |
| :------------- | ---------: |
| **HttpRouter** | **21,680** |
| **Gin**        | **34,408** |
| **Macaron**    | **36,976** |
| BunRouter      |     51,232 |
| Fiber          |     59,248 |
| HttpServeMux   |     71,728 |
| HttpTreeMux    |     73,448 |
| Chi            |     83,160 |
| Echo           |     91,976 |
| Beego          |     98,824 |
| Goji v2        |    117,952 |
| GorillaMux     |    599,496 |
| GoRestful      |    819,704 |

### GitHub API Routes: 203

| Router          |      Bytes |
| :-------------- | ---------: |
| **HttpRouter**  | **37,072** |
| **Gin**         | **58,840** |
| **HttpTreeMux** | **78,800** |
| Macaron         |     90,632 |
| BunRouter       |     93,776 |
| Chi             |     94,888 |
| Echo            |    117,784 |
| Goji v2         |    118,640 |
| Beego           |    150,840 |
| Fiber           |    163,832 |
| GoRestful       |  1,270,848 |
| GorillaMux      |  1,319,696 |

### Google+ API Routes: 13

| Router         |     Bytes |
| :------------- | --------: |
| **HttpRouter** | **2,776** |
| **Gin**        | **4,576** |
| **BunRouter**  | **7,360** |
| HttpTreeMux    |     7,440 |
| Chi            |     8,008 |
| Goji v2        |     8,096 |
| Macaron        |     8,672 |
| Beego          |    10,256 |
| Fiber          |    10,840 |
| Echo           |    10,968 |
| GorillaMux     |    68,000 |
| GoRestful      |    72,536 |

### Parse API Routes: 26

| Router          |     Bytes |
| :-------------- | --------: |
| **HttpRouter**  | **5,024** |
| **Gin**         | **7,896** |
| **HttpTreeMux** | **7,848** |
| BunRouter       |     9,336 |
| Chi             |     9,656 |
| Echo            |    13,816 |
| Macaron         |    13,704 |
| Fiber           |    15,352 |
| Goji v2         |    16,064 |
| Beego           |    19,256 |
| GorillaMux      |   105,384 |
| GoRestful       |   121,200 |

---

## Benchmark Results

### GitHub API (203 routes)

Routing all 203 GitHub API endpoints per operation.

| Rank | Router        |     ns/op |      B/op | allocs/op |
| :--: | :------------ | --------: | --------: | --------: |
|  1   | **Gin**       |     9,944 |         0 |         0 |
|  2   | **BunRouter** |    10,281 |         0 |         0 |
|  3   | **Echo**      |    11,072 |         0 |         0 |
|  4   | HttpRouter    |    15,059 |    13,792 |       167 |
|  5   | HttpTreeMux   |    49,302 |    65,856 |       671 |
|  6   | Chi           |    94,376 |   130,817 |       740 |
|  7   | Beego         |   101,941 |    71,456 |       609 |
|  8   | Fiber         |   109,148 |         0 |         0 |
|  9   | Macaron       |   121,785 |   147,784 |     1,624 |
|  10  | Goji v2       |   242,849 |   313,744 |     3,712 |
|  11  | GoRestful     |   885,678 | 1,006,744 |     3,009 |
|  12  | GorillaMux    | 1,316,844 |   225,667 |     1,588 |

### Google+ API (13 routes)

Routing all 13 Google+ API endpoints per operation.

| Rank | Router        |  ns/op |   B/op | allocs/op |
| :--: | :------------ | -----: | -----: | --------: |
|  1   | **BunRouter** |  348.5 |      0 |         0 |
|  2   | **Gin**       |  429.7 |      0 |         0 |
|  3   | **Echo**      |  451.1 |      0 |         0 |
|  4   | HttpRouter    |  668.6 |    640 |        11 |
|  5   | HttpTreeMux   |  2,428 |  4,032 |        38 |
|  6   | Fiber         |  2,506 |      0 |         0 |
|  7   | Chi           |  5,333 |  8,480 |        48 |
|  8   | Beego         |  5,927 |  4,576 |        39 |
|  9   | Macaron       |  7,294 |  9,464 |       104 |
|  10  | Goji v2       |  8,000 | 15,120 |       115 |
|  11  | GorillaMux    | 14,707 | 14,448 |       102 |
|  12  | GoRestful     | 24,189 | 60,720 |       193 |

### Parse API (26 routes)

Routing all 26 Parse API endpoints per operation.

| Rank | Router        |  ns/op |    B/op | allocs/op |
| :--: | :------------ | -----: | ------: | --------: |
|  1   | **BunRouter** |  588.2 |       0 |         0 |
|  2   | **Gin**       |  712.1 |       0 |         0 |
|  3   | **Echo**      |  742.1 |       0 |         0 |
|  4   | HttpRouter    |  948.5 |     640 |        16 |
|  5   | HttpTreeMux   |  3,372 |   5,728 |        51 |
|  6   | Fiber         |  4,250 |       0 |         0 |
|  7   | Chi           |  8,863 |  14,944 |        84 |
|  8   | Beego         | 10,541 |   9,152 |        78 |
|  9   | Macaron       | 13,635 |  18,928 |       208 |
|  10  | Goji v2       | 13,264 |  29,456 |       199 |
|  11  | GorillaMux    | 25,886 |  26,960 |       198 |
|  12  | GoRestful     | 54,780 | 131,728 |       380 |

### Static Routes (157 routes)

Routing all 157 static routes per operation. Includes http.ServeMux as baseline.

| Rank | Router          |   ns/op |    B/op | allocs/op |
| :--: | :-------------- | ------: | ------: | --------: |
|  1   | **HttpRouter**  |   4,177 |       0 |         0 |
|  2   | **HttpTreeMux** |   5,363 |       0 |         0 |
|  3   | **Gin**         |   5,528 |       0 |         0 |
|  4   | BunRouter       |   5,997 |       0 |         0 |
|  5   | Echo            |   6,897 |       0 |         0 |
|  —   | HttpServeMux    |  18,172 |       0 |         0 |
|  6   | Fiber           |  29,310 |       0 |         0 |
|  7   | Chi             |  41,317 |  57,776 |       314 |
|  8   | Beego           |  68,255 |  55,264 |       471 |
|  9   | Macaron         |  81,824 | 114,296 |     1,256 |
|  10  | Goji v2         |  84,459 | 175,840 |     1,099 |
|  11  | GorillaMux      | 302,825 | 133,137 |     1,099 |
|  12  | GoRestful       | 436,510 | 677,824 |     2,193 |

---

## Micro Benchmarks

### Single Param

Route: `/user/:name` — Request: `GET /user/gordon`

| Rank | Router        | ns/op |  B/op | allocs/op |
| :--: | :------------ | ----: | ----: | --------: |
|  1   | **BunRouter** | 12.22 |     0 |         0 |
|  2   | **Echo**      | 17.75 |     0 |         0 |
|  3   | **Gin**       | 23.31 |     0 |         0 |
|  4   | HttpRouter    | 31.88 |    32 |         1 |
|  5   | Fiber         | 114.4 |     0 |         0 |
|  6   | HttpTreeMux   | 165.0 |   352 |         3 |
|  7   | Chi           | 332.2 |   704 |         4 |
|  8   | Beego         | 348.8 |   352 |         3 |
|  9   | Goji v2       | 494.3 | 1,136 |         8 |
|  10  | GorillaMux    | 630.6 | 1,152 |         8 |
|  11  | Macaron       | 708.0 | 1,064 |        10 |
|  12  | GoRestful     | 1,394 | 4,600 |        15 |

### 5 Params

Route: `/:a/:b/:c/:d/:e` — Request: `GET /test/test/test/test/test`

| Rank | Router        | ns/op |  B/op | allocs/op |
| :--: | :------------ | ----: | ----: | --------: |
|  1   | **BunRouter** | 41.86 |     0 |         0 |
|  2   | **Echo**      | 43.76 |     0 |         0 |
|  3   | **Gin**       | 44.20 |     0 |         0 |
|  4   | HttpRouter    | 83.74 |   160 |         1 |
|  5   | Fiber         | 271.6 |     0 |         0 |
|  6   | HttpTreeMux   | 358.8 |   576 |         6 |
|  7   | Chi           | 453.7 |   704 |         4 |
|  8   | Beego         | 480.3 |   352 |         3 |
|  9   | Goji v2       | 532.4 | 1,200 |         8 |
|  10  | Macaron       | 799.7 | 1,064 |        10 |
|  11  | GorillaMux    | 972.6 | 1,216 |         8 |
|  12  | GoRestful     | 1,579 | 4,712 |        15 |

### 20 Params

Route: `/:a/:b/.../:t` (20 segments) — Request: `GET /a/b/.../t`

| Rank | Router        | ns/op |  B/op | allocs/op |
| :--: | :------------ | ----: | ----: | --------: |
|  1   | **Gin**       | 121.7 |     0 |         0 |
|  2   | **Echo**      | 127.5 |     0 |         0 |
|  3   | **BunRouter** | 211.4 |     0 |         0 |
|  4   | HttpRouter    | 290.2 |   704 |         1 |
|  5   | Fiber         | 466.1 |     0 |         0 |
|  6   | Goji v2       | 745.3 | 1,440 |         8 |
|  7   | Beego         | 1,099 |   352 |         3 |
|  8   | Chi           | 1,805 | 2,504 |         9 |
|  9   | HttpTreeMux   | 1,857 | 3,144 |        13 |
|  10  | Macaron       | 2,058 | 2,864 |        15 |
|  11  | GorillaMux    | 2,223 | 3,272 |        13 |
|  12  | GoRestful     | 3,337 | 7,008 |        20 |

### Param Write

Route: `/user/:name` with response write — Request: `GET /user/gordon`

| Rank | Router        | ns/op |  B/op | allocs/op |
| :--: | :------------ | ----: | ----: | --------: |
|  1   | **BunRouter** | 25.86 |     0 |         0 |
|  2   | **Gin**       | 27.65 |     0 |         0 |
|  3   | HttpRouter    | 37.40 |    32 |         1 |
|  4   | Echo          | 47.94 |     8 |         1 |
|  5   | Fiber         | 125.7 |     0 |         0 |
|  6   | HttpTreeMux   | 180.4 |   352 |         3 |
|  7   | Chi           | 348.3 |   704 |         4 |
|  8   | Beego         | 386.1 |   360 |         4 |
|  9   | Goji v2       | 516.9 | 1,168 |        10 |
|  10  | GorillaMux    | 665.5 | 1,152 |         8 |
|  11  | Macaron       | 784.3 | 1,112 |        13 |
|  12  | GoRestful     | 1,534 | 4,608 |        16 |


================================================
FILE: CHANGELOG.md
================================================
# Gin ChangeLog

## Gin v1.12.0

### Features

- feat(render): add bson protocol ([#4145](https://github.com/gin-gonic/gin/pull/4145))
- feat(context): add GetError and GetErrorSlice methods for error retrieval ([#4502](https://github.com/gin-gonic/gin/pull/4502))
- feat(binding): add support for encoding.UnmarshalText in uri/query binding ([#4203](https://github.com/gin-gonic/gin/pull/4203))
- feat(gin): add option to use escaped path ([#4420](https://github.com/gin-gonic/gin/pull/4420))
- feat(context): add Protocol Buffers support to content negotiation ([#4423](https://github.com/gin-gonic/gin/pull/4423))
- feat(context): implemented Delete method ([#38e7651](https://github.com/gin-gonic/gin/commit/38e7651))
- feat(logger): color latency ([#4146](https://github.com/gin-gonic/gin/pull/4146))

### Enhancements

- perf(tree): reduce allocations in findCaseInsensitivePath ([#4417](https://github.com/gin-gonic/gin/pull/4417))
- perf(recovery): optimize line reading in stack function ([#4466](https://github.com/gin-gonic/gin/pull/4466))
- perf(path): replace regex with custom functions in redirectTrailingSlash ([#4414](https://github.com/gin-gonic/gin/pull/4414))
- perf(tree): optimize path parsing using strings.Count ([#4246](https://github.com/gin-gonic/gin/pull/4246))
- chore(logger): allow skipping query string output ([#4547](https://github.com/gin-gonic/gin/pull/4547))
- chore(context): always trust xff headers from unix socket ([#3359](https://github.com/gin-gonic/gin/pull/3359))
- chore(response): prevent Flush() panic when the underlying ResponseWriter does not implement `http.Flusher` ([#4479](https://github.com/gin-gonic/gin/pull/4479))
- refactor(recovery): smart error comparison ([#4142](https://github.com/gin-gonic/gin/pull/4142))
- refactor(context): replace hardcoded localhost IPs with constants ([#4481](https://github.com/gin-gonic/gin/pull/4481))
- refactor(utils): move util functions to utils.go ([#4467](https://github.com/gin-gonic/gin/pull/4467))
- refactor(binding): use maps.Copy for cleaner map handling ([#4352](https://github.com/gin-gonic/gin/pull/4352))
- refactor(context): using maps.Clone ([#4333](https://github.com/gin-gonic/gin/pull/4333))
- refactor(ginS): use sync.OnceValue to simplify engine function ([#4314](https://github.com/gin-gonic/gin/pull/4314))
- refactor: replace magic numbers with named constants in bodyAllowedForStatus ([#4529](https://github.com/gin-gonic/gin/pull/4529))
- refactor: for loop can be modernized using range over int ([#4392](https://github.com/gin-gonic/gin/pull/4392))

### Bug Fixes

- fix(tree): panic in findCaseInsensitivePathRec with RedirectFixedPath ([#4535](https://github.com/gin-gonic/gin/pull/4535))
- fix(render): write content length in Data.Render ([#4206](https://github.com/gin-gonic/gin/pull/4206))
- fix(context): ClientIP handling for multiple X-Forwarded-For header values ([#4472](https://github.com/gin-gonic/gin/pull/4472))
- fix(binding): empty value error ([#2169](https://github.com/gin-gonic/gin/pull/2169))
- fix(recover): suppress http.ErrAbortHandler in recover ([#4336](https://github.com/gin-gonic/gin/pull/4336))
- fix(gin): literal colon routes not working with engine.Handler() ([#4415](https://github.com/gin-gonic/gin/pull/4415))
- fix(gin): close os.File in RunFd to prevent resource leak ([#4422](https://github.com/gin-gonic/gin/pull/4422))
- fix(response): refine hijack behavior for response lifecycle ([#4373](https://github.com/gin-gonic/gin/pull/4373))
- fix(binding): improve empty slice/array handling in form binding ([#4380](https://github.com/gin-gonic/gin/pull/4380))
- fix(debug): version mismatch ([#4403](https://github.com/gin-gonic/gin/pull/4403))
- fix: correct typos, improve documentation clarity, and remove dead code ([#4511](https://github.com/gin-gonic/gin/pull/4511))

### Build process updates / CI

- ci: update Go version support to 1.25+ across CI and docs ([#4550](https://github.com/gin-gonic/gin/pull/4550))
- chore(binding): upgrade bson dependency to mongo-driver v2 ([#4549](https://github.com/gin-gonic/gin/pull/4549))

## Gin v1.11.0

### Features

- feat(gin): Experimental support for HTTP/3 using quic-go/quic-go ([#3210](https://github.com/gin-gonic/gin/pull/3210))
- feat(form): add array collection format in form binding ([#3986](https://github.com/gin-gonic/gin/pull/3986)), add custom string slice for form tag unmarshal ([#3970](https://github.com/gin-gonic/gin/pull/3970))
- feat(binding): add BindPlain ([#3904](https://github.com/gin-gonic/gin/pull/3904))
- feat(fs): Export, test and document OnlyFilesFS ([#3939](https://github.com/gin-gonic/gin/pull/3939))
- feat(binding): add support for unixMilli and unixMicro ([#4190](https://github.com/gin-gonic/gin/pull/4190))
- feat(form): Support default values for collections in form binding ([#4048](https://github.com/gin-gonic/gin/pull/4048))
- feat(context): GetXxx added support for more go native types ([#3633](https://github.com/gin-gonic/gin/pull/3633))

### Enhancements

- perf(context): optimize getMapFromFormData performance ([#4339](https://github.com/gin-gonic/gin/pull/4339))
- refactor(tree): replace string(/) with "/" in node.insertChild ([#4354](https://github.com/gin-gonic/gin/pull/4354))
- refactor(render): remove headers parameter from writeHeader ([#4353](https://github.com/gin-gonic/gin/pull/4353))
- refactor(context): simplify "GetType()" functions ([#4080](https://github.com/gin-gonic/gin/pull/4080))
- refactor(slice): simplify SliceValidationError Error method ([#3910](https://github.com/gin-gonic/gin/pull/3910))
- refactor(context):Avoid using filepath.Dir twice in SaveUploadedFile ([#4181](https://github.com/gin-gonic/gin/pull/4181))
- refactor(context): refactor context handling and improve test robustness ([#4066](https://github.com/gin-gonic/gin/pull/4066))
- refactor(binding): use strings.Cut to replace strings.Index ([#3522](https://github.com/gin-gonic/gin/pull/3522))
- refactor(context): add an optional permission parameter to SaveUploadedFile ([#4068](https://github.com/gin-gonic/gin/pull/4068))
- refactor(context): verify URL is Non-nil in initQueryCache() ([#3969](https://github.com/gin-gonic/gin/pull/3969))
- refactor(context): YAML judgment logic in Negotiate ([#3966](https://github.com/gin-gonic/gin/pull/3966))
- tree: replace the self-defined 'min' to official one ([#3975](https://github.com/gin-gonic/gin/pull/3975))
- context: Remove redundant filepath.Dir usage ([#4181](https://github.com/gin-gonic/gin/pull/4181))

### Bug Fixes

- fix: prevent middleware re-entry issue in HandleContext ([#3987](https://github.com/gin-gonic/gin/pull/3987))
- fix(binding): prevent duplicate decoding and add validation in decodeToml ([#4193](https://github.com/gin-gonic/gin/pull/4193))
- fix(gin): Do not panic when handling method not allowed on empty tree ([#4003](https://github.com/gin-gonic/gin/pull/4003))
- fix(gin): data race warning for gin mode ([#1580](https://github.com/gin-gonic/gin/pull/1580))
- fix(context): verify URL is Non-nil in initQueryCache() ([#3969](https://github.com/gin-gonic/gin/pull/3969))
- fix(context): YAML judgment logic in Negotiate ([#3966](https://github.com/gin-gonic/gin/pull/3966))
- fix(context): check handler is nil ([#3413](https://github.com/gin-gonic/gin/pull/3413))
- fix(readme): fix broken link to English documentation ([#4222](https://github.com/gin-gonic/gin/pull/4222))
- fix(tree): Keep panic infos consistent when wildcard type build faild ([#4077](https://github.com/gin-gonic/gin/pull/4077))

### Build process updates / CI

- ci: integrate Trivy vulnerability scanning into CI workflow ([#4359](https://github.com/gin-gonic/gin/pull/4359))
- ci: support Go 1.25 in CI/CD ([#4341](https://github.com/gin-gonic/gin/pull/4341))
- build(deps): upgrade github.com/bytedance/sonic from v1.13.2 to v1.14.0 ([#4342](https://github.com/gin-gonic/gin/pull/4342))
- ci: add Go version 1.24 to GitHub Actions ([#4154](https://github.com/gin-gonic/gin/pull/4154))
- build: update Gin minimum Go version to 1.21 ([#3960](https://github.com/gin-gonic/gin/pull/3960))
- ci(lint): enable new linters (testifylint, usestdlibvars, perfsprint, etc.) ([#4010](https://github.com/gin-gonic/gin/pull/4010), [#4091](https://github.com/gin-gonic/gin/pull/4091), [#4090](https://github.com/gin-gonic/gin/pull/4090))
- ci(lint): update workflows and improve test request consistency ([#4126](https://github.com/gin-gonic/gin/pull/4126))

### Dependency updates

- chore(deps): bump google.golang.org/protobuf from 1.36.6 to 1.36.9 ([#4346](https://github.com/gin-gonic/gin/pull/4346), [#4356](https://github.com/gin-gonic/gin/pull/4356))
- chore(deps): bump github.com/stretchr/testify from 1.10.0 to 1.11.1 ([#4347](https://github.com/gin-gonic/gin/pull/4347))
- chore(deps): bump actions/setup-go from 5 to 6 ([#4351](https://github.com/gin-gonic/gin/pull/4351))
- chore(deps): bump github.com/quic-go/quic-go from 0.53.0 to 0.54.0 ([#4328](https://github.com/gin-gonic/gin/pull/4328))
- chore(deps): bump golang.org/x/net from 0.33.0 to 0.38.0 ([#4178](https://github.com/gin-gonic/gin/pull/4178), [#4221](https://github.com/gin-gonic/gin/pull/4221))
- chore(deps): bump github.com/go-playground/validator/v10 from 10.20.0 to 10.22.1 ([#4052](https://github.com/gin-gonic/gin/pull/4052))

### Documentation updates

- docs(changelog): update release notes for Gin v1.10.1 ([#4360](https://github.com/gin-gonic/gin/pull/4360))
- docs: Fixing English grammar mistakes and awkward sentence structure in doc/doc.md ([#4207](https://github.com/gin-gonic/gin/pull/4207))
- docs: update documentation and release notes for Gin v1.10.0 ([#3953](https://github.com/gin-gonic/gin/pull/3953))
- docs: fix typo in Gin Quick Start ([#3997](https://github.com/gin-gonic/gin/pull/3997))
- docs: fix comment and link issues ([#4205](https://github.com/gin-gonic/gin/pull/4205), [#3938](https://github.com/gin-gonic/gin/pull/3938))
- docs: fix route group example code ([#4020](https://github.com/gin-gonic/gin/pull/4020))
- docs(readme): add Portuguese documentation ([#4078](https://github.com/gin-gonic/gin/pull/4078))
- docs(context): fix some function names in comment ([#4079](https://github.com/gin-gonic/gin/pull/4079))

---

## Gin v1.10.1

### Features

- refactor: strengthen HTTPS security and improve code organization
- feat(binding): Support custom BindUnmarshaler for binding. (#3933)

### Enhancements

- chore(deps): bump github.com/bytedance/sonic from 1.11.3 to 1.11.6 (#3940)
- chore(deps): bump golangci/golangci-lint-action from 4 to 5 (#3941)
- chore: update external dependencies to latest versions (#3950)
- chore: update various Go dependencies to latest versions (#3901)
- chore: refactor configuration files for better readability (#3951)
- chore: update changelog categories and improve documentation (#3917)
- feat: update version constant to v1.10.0 (#3952)

### Build process updates

- ci(release): refactor changelog regex patterns and exclusions (#3914)
- ci(Makefile): vet command add .PHONY (#3915)

## Gin v1.10.0

### Features

- feat(auth): add proxy-server authentication (#3877) (@EndlessParadox1)
- feat(bind): ShouldBindBodyWith shortcut and change doc (#3871) (@RedCrazyGhost)
- feat(binding): Support custom BindUnmarshaler for binding. (#3933) (@dkkb)
- feat(binding): support override default binding implement (#3514) (@ssfyn)
- feat(engine): Added `OptionFunc` and `With` (#3572) (@flc1125)
- feat(logger): ability to skip logs based on user-defined logic (#3593) (@palvaneh)

### Bug fixes

- Revert "fix(uri): query binding bug (#3236)" (#3899) (@appleboy)
- fix(binding): binding error while not upload file (#3819) (#3820) (@clearcodecn)
- fix(binding): dereference pointer to struct (#3199) (@echovl)
- fix(context): make context Value method adhere to Go standards (#3897) (@FarmerChillax)
- fix(engine): fix unit test (#3878) (@flc1125)
- fix(header): Allow header according to RFC 7231 (HTTP 405) (#3759) (@Crocmagnon)
- fix(route): Add fullPath in context copy (#3784) (@KarthikReddyPuli)
- fix(router): catch-all conflicting wildcard (#3812) (@FirePing32)
- fix(sec): upgrade golang.org/x/crypto to 0.17.0 (#3832) (@chncaption)
- fix(tree): correctly expand the capacity of params (#3502) (@georgijd-form3)
- fix(uri): query binding bug (#3236) (@illiafox)
- fix: Add pointer support for url query params (#3659) (#3666) (@omkar-foss)
- fix: protect Context.Keys map when call Copy method (#3873) (@kingcanfish)

### Enhancements

- chore(CI): update release args (#3595) (@qloog)
- chore(IP): add TrustedPlatform constant for Fly.io. (#3839) (@ab)
- chore(debug): add ability to override the debugPrint statement (#2337) (@josegonzalez)
- chore(deps): update dependencies to latest versions (#3835) (@appleboy)
- chore(header): Add support for RFC 9512: application/yaml (#3851) (@vincentbernat)
- chore(http): use white color for HTTP 1XX (#3741) (@viralparmarme)
- chore(optimize): the ShouldBindUri method of the Context struct (#3911) (@1911860538)
- chore(perf): Optimize the Copy method of the Context struct (#3859) (@1911860538)
- chore(refactor): modify interface check way (#3855) (@demoManito)
- chore(request): check reader if it's nil before reading (#3419) (@noahyao1024)
- chore(security): upgrade Protobuf for CVE-2024-24786 (#3893) (@Fotkurz)
- chore: refactor CI and update dependencies (#3848) (@appleboy)
- chore: refactor configuration files for better readability (#3951) (@appleboy)
- chore: update GitHub Actions configuration (#3792) (@appleboy)
- chore: update changelog categories and improve documentation (#3917) (@appleboy)
- chore: update dependencies to latest versions (#3694) (@appleboy)
- chore: update external dependencies to latest versions (#3950) (@appleboy)
- chore: update various Go dependencies to latest versions (#3901) (@appleboy)

### Build process updates

- build(codecov): Added a codecov configuration (#3891) (@flc1125)
- ci(Makefile): vet command add .PHONY (#3915) (@imalasong)
- ci(lint): update tooling and workflows for consistency (#3834) (@appleboy)
- ci(release): refactor changelog regex patterns and exclusions (#3914) (@appleboy)
- ci(testing): add go1.22 version (#3842) (@appleboy)

### Documentation updates

- docs(context): Added deprecation comments to BindWith (#3880) (@flc1125)
- docs(middleware): comments to function `BasicAuthForProxy` (#3881) (@EndlessParadox1)
- docs: Add document to constant `AuthProxyUserKey` and `BasicAuthForProxy`. (#3887) (@EndlessParadox1)
- docs: fix typo in comment (#3868) (@testwill)
- docs: fix typo in function documentation (#3872) (@TotomiEcio)
- docs: remove redundant comments (#3765) (@WeiTheShinobi)
- feat: update version constant to v1.10.0 (#3952) (@appleboy)

### Others

- Upgrade golang.org/x/net -> v0.13.0 (#3684) (@cpcf)
- test(git): gitignore add develop tools (#3370) (@demoManito)
- test(http): use constant instead of numeric literal (#3863) (@testwill)
- test(path): Optimize unit test execution results (#3883) (@flc1125)
- test(render): increased unit tests coverage (#3691) (@araujo88)

## Gin v1.9.1

### BUG FIXES

- fix Request.Context() checks [#3512](https://github.com/gin-gonic/gin/pull/3512)

### SECURITY

- fix lack of escaping of filename in Content-Disposition [#3556](https://github.com/gin-gonic/gin/pull/3556)

### ENHANCEMENTS

- refactor: use bytes.ReplaceAll directly [#3455](https://github.com/gin-gonic/gin/pull/3455)
- convert strings and slices using the officially recommended way [#3344](https://github.com/gin-gonic/gin/pull/3344)
- improve render code coverage [#3525](https://github.com/gin-gonic/gin/pull/3525)

### DOCS

- docs: changed documentation link for trusted proxies [#3575](https://github.com/gin-gonic/gin/pull/3575)
- chore: improve linting, testing, and GitHub Actions setup [#3583](https://github.com/gin-gonic/gin/pull/3583)

## Gin v1.9.0

### BREAK CHANGES

- Stop useless panicking in context and render [#2150](https://github.com/gin-gonic/gin/pull/2150)

### BUG FIXES

- fix(router): tree bug where loop index is not decremented. [#3460](https://github.com/gin-gonic/gin/pull/3460)
- fix(context): panic on NegotiateFormat - index out of range [#3397](https://github.com/gin-gonic/gin/pull/3397)
- Add escape logic for header [#3500](https://github.com/gin-gonic/gin/pull/3500) and [#3503](https://github.com/gin-gonic/gin/pull/3503)

### SECURITY

- Fix the GO-2022-0969 and GO-2022-0288 vulnerabilities [#3333](https://github.com/gin-gonic/gin/pull/3333)
- fix(security): vulnerability GO-2023-1571 [#3505](https://github.com/gin-gonic/gin/pull/3505)

### ENHANCEMENTS

- feat: add sonic json support [#3184](https://github.com/gin-gonic/gin/pull/3184)
- chore(file): Creates a directory named path [#3316](https://github.com/gin-gonic/gin/pull/3316)
- fix: modify interface check way [#3327](https://github.com/gin-gonic/gin/pull/3327)
- remove deprecated of package io/ioutil [#3395](https://github.com/gin-gonic/gin/pull/3395)
- refactor: avoid calling strings.ToLower twice [#3343](https://github.com/gin-gonic/gin/pull/3433)
- console logger HTTP status code bug fixed [#3453](https://github.com/gin-gonic/gin/pull/3453)
- chore(yaml): upgrade dependency to v3 version [#3456](https://github.com/gin-gonic/gin/pull/3456)
- chore(router): match method added to routergroup for multiple HTTP methods supporting [#3464](https://github.com/gin-gonic/gin/pull/3464)
- chore(http): add support for go1.20 http.rwUnwrapper to gin.responseWriter [#3489](https://github.com/gin-gonic/gin/pull/3489)

### DOCS

- docs: update markdown format [#3260](https://github.com/gin-gonic/gin/pull/3260)
- docs(readme): Add the TOML rendering example [#3400](https://github.com/gin-gonic/gin/pull/3400)
- docs(readme): move more example to docs/doc.md [#3449](https://github.com/gin-gonic/gin/pull/3449)
- docs: update markdown format [#3446](https://github.com/gin-gonic/gin/pull/3446)

## Gin v1.8.2

### BUG FIXES

- fix(route): redirectSlash bug ([#3227](<(https://github.com/gin-gonic/gin/pull/3227)>))
- fix(engine): missing route params for CreateTestContext ([#2778](<(https://github.com/gin-gonic/gin/pull/2778)>)) ([#2803](<(https://github.com/gin-gonic/gin/pull/2803)>))

### SECURITY

- Fix the GO-2022-1144 vulnerability ([#3432](<(https://github.com/gin-gonic/gin/pull/3432)>))

## 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)

### BUG FIXES

- 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

### BUG FIXES

- Fixed X-Forwarded-For unsafe handling of CVE-2020-28483 [#2844](https://github.com/gin-gonic/gin/pull/2844), closed issue [#2862](https://github.com/gin-gonic/gin/issues/2862).
- Tree: updated the code logic for `latestNode` [#2897](https://github.com/gin-gonic/gin/pull/2897), closed issue [#2894](https://github.com/gin-gonic/gin/issues/2894) [#2878](https://github.com/gin-gonic/gin/issues/2878).
- Tree: fixed the misplacement of adding slashes [#2847](https://github.com/gin-gonic/gin/pull/2847), closed issue [#2843](https://github.com/gin-gonic/gin/issues/2843).
- Tree: fixed tsr with mixed static and wildcard paths [#2924](https://github.com/gin-gonic/gin/pull/2924), closed issue [#2918](https://github.com/gin-gonic/gin/issues/2918).

### ENHANCEMENTS

- TrustedProxies: make it backward-compatible [#2887](https://github.com/gin-gonic/gin/pull/2887), closed issue [#2819](https://github.com/gin-gonic/gin/issues/2819).
- TrustedPlatform: provide custom options for another CDN services [#2906](https://github.com/gin-gonic/gin/pull/2906).

### DOCS

- NoMethod: added usage annotation ([#2832](https://github.com/gin-gonic/gin/pull/2832#issuecomment-929954463)).

## Gin v1.7.6

### BUG FIXES

- bump new release to fix v1.7.5 release error by using v1.7.4 codes.

## Gin v1.7.4

### BUG FIXES

- bump new release to fix checksum mismatch

## Gin v1.7.3

### BUG FIXES

- fix level 1 router match [#2767](https://github.com/gin-gonic/gin/issues/2767), [#2796](https://github.com/gin-gonic/gin/issues/2796)

## Gin v1.7.2

### BUG FIXES

- Fix conflict between param and exact path [#2706](https://github.com/gin-gonic/gin/issues/2706). Close issue [#2682](https://github.com/gin-gonic/gin/issues/2682) [#2696](https://github.com/gin-gonic/gin/issues/2696).

## Gin v1.7.1

### BUG FIXES

- fix: data race with trustedCIDRs from [#2674](https://github.com/gin-gonic/gin/issues/2674)([#2675](https://github.com/gin-gonic/gin/pull/2675))

## Gin v1.7.0

### BUG FIXES

- fix compile error from [#2572](https://github.com/gin-gonic/gin/pull/2572) ([#2600](https://github.com/gin-gonic/gin/pull/2600))
- fix: print headers without Authorization header on broken pipe ([#2528](https://github.com/gin-gonic/gin/pull/2528))
- fix(tree): reassign fullpath when register new node ([#2366](https://github.com/gin-gonic/gin/pull/2366))

### ENHANCEMENTS

- Support params and exact routes without creating conflicts ([#2663](https://github.com/gin-gonic/gin/pull/2663))
- chore: improve render string performance ([#2365](https://github.com/gin-gonic/gin/pull/2365))
- Sync route tree to httprouter latest code ([#2368](https://github.com/gin-gonic/gin/pull/2368))
- chore: rename getQueryCache/getFormCache to initQueryCache/initFormCa ([#2375](https://github.com/gin-gonic/gin/pull/2375))
- chore(performance): improve countParams ([#2378](https://github.com/gin-gonic/gin/pull/2378))
- Remove some functions that have the same effect as the bytes package ([#2387](https://github.com/gin-gonic/gin/pull/2387))
- update:SetMode function ([#2321](https://github.com/gin-gonic/gin/pull/2321))
- remove an unused type SecureJSONPrefix ([#2391](https://github.com/gin-gonic/gin/pull/2391))
- Add a redirect sample for POST method ([#2389](https://github.com/gin-gonic/gin/pull/2389))
- Add CustomRecovery builtin middleware ([#2322](https://github.com/gin-gonic/gin/pull/2322))
- binding: avoid 2038 problem on 32-bit architectures ([#2450](https://github.com/gin-gonic/gin/pull/2450))
- Prevent panic in Context.GetQuery() when there is no Request ([#2412](https://github.com/gin-gonic/gin/pull/2412))
- Add GetUint and GetUint64 method on gin.context ([#2487](https://github.com/gin-gonic/gin/pull/2487))
- update content-disposition header to MIME-style ([#2512](https://github.com/gin-gonic/gin/pull/2512))
- reduce allocs and improve the render `WriteString` ([#2508](https://github.com/gin-gonic/gin/pull/2508))
- implement ".Unwrap() error" on Error type ([#2525](https://github.com/gin-gonic/gin/pull/2525)) ([#2526](https://github.com/gin-gonic/gin/pull/2526))
- Allow bind with a map[string]string ([#2484](https://github.com/gin-gonic/gin/pull/2484))
- chore: update tree ([#2371](https://github.com/gin-gonic/gin/pull/2371))
- Support binding for slice/array obj [Rewrite] ([#2302](https://github.com/gin-gonic/gin/pull/2302))
- basic auth: fix timing oracle ([#2609](https://github.com/gin-gonic/gin/pull/2609))
- Add mixed param and non-param paths (port of httprouter[#329](https://github.com/gin-gonic/gin/pull/329)) ([#2663](https://github.com/gin-gonic/gin/pull/2663))
- feat(engine): add trustedproxies and remoteIP ([#2632](https://github.com/gin-gonic/gin/pull/2632))

## Gin v1.6.3

### ENHANCEMENTS

- Improve performance: Change `*sync.RWMutex` to `sync.RWMutex` in context. [#2351](https://github.com/gin-gonic/gin/pull/2351)

## Gin v1.6.2

### BUG FIXES

- fix missing initial sync.RWMutex [#2305](https://github.com/gin-gonic/gin/pull/2305)

### ENHANCEMENTS

- Add set samesite in cookie. [#2306](https://github.com/gin-gonic/gin/pull/2306)

## Gin v1.6.1

### BUG FIXES

- Revert "fix accept incoming network connections" [#2294](https://github.com/gin-gonic/gin/pull/2294)

## Gin v1.6.0

### BREAKING

- chore(performance): Improve performance for adding RemoveExtraSlash flag [#2159](https://github.com/gin-gonic/gin/pull/2159)
- drop support govendor [#2148](https://github.com/gin-gonic/gin/pull/2148)
- Added support for SameSite cookie flag [#1615](https://github.com/gin-gonic/gin/pull/1615)

### FEATURES

- add yaml negotiation [#2220](https://github.com/gin-gonic/gin/pull/2220)
- FileFromFS [#2112](https://github.com/gin-gonic/gin/pull/2112)

### BUG FIXES

- Unix Socket Handling [#2280](https://github.com/gin-gonic/gin/pull/2280)
- Use json marshall in context json to fix breaking new line issue. Fixes #2209 [#2228](https://github.com/gin-gonic/gin/pull/2228)
- fix accept incoming network connections [#2216](https://github.com/gin-gonic/gin/pull/2216)
- Fixed a bug in the calculation of the maximum number of parameters [#2166](https://github.com/gin-gonic/gin/pull/2166)
- [FIX] allow empty headers on DataFromReader [#2121](https://github.com/gin-gonic/gin/pull/2121)
- Add mutex for protect Context.Keys map [#1391](https://github.com/gin-gonic/gin/pull/1391)

### ENHANCEMENTS

- Add mitigation for log injection [#2277](https://github.com/gin-gonic/gin/pull/2277)
- tree: range over nodes values [#2229](https://github.com/gin-gonic/gin/pull/2229)
- tree: remove duplicate assignment [#2222](https://github.com/gin-gonic/gin/pull/2222)
- chore: upgrade go-isatty and json-iterator/go [#2215](https://github.com/gin-gonic/gin/pull/2215)
- path: sync code with httprouter [#2212](https://github.com/gin-gonic/gin/pull/2212)
- Use zero-copy approach to convert types between string and byte slice [#2206](https://github.com/gin-gonic/gin/pull/2206)
- Reuse bytes when cleaning the URL paths [#2179](https://github.com/gin-gonic/gin/pull/2179)
- tree: remove one else statement [#2177](https://github.com/gin-gonic/gin/pull/2177)
- tree: sync httprouter update (#2173) (#2172) [#2171](https://github.com/gin-gonic/gin/pull/2171)
- tree: sync part httprouter codes and reduce if/else [#2163](https://github.com/gin-gonic/gin/pull/2163)
- use http method constant [#2155](https://github.com/gin-gonic/gin/pull/2155)
- upgrade go-validator to v10 [#2149](https://github.com/gin-gonic/gin/pull/2149)
- Refactor redirect request in gin.go [#1970](https://github.com/gin-gonic/gin/pull/1970)
- Add build tag nomsgpack [#1852](https://github.com/gin-gonic/gin/pull/1852)

### DOCS

- docs(path): improve comments [#2223](https://github.com/gin-gonic/gin/pull/2223)
- Renew README to fit the modification of SetCookie method [#2217](https://github.com/gin-gonic/gin/pull/2217)
- Fix spelling [#2202](https://github.com/gin-gonic/gin/pull/2202)
- Remove broken link from README. [#2198](https://github.com/gin-gonic/gin/pull/2198)
- Update docs on Context.Done(), Context.Deadline() and Context.Err() [#2196](https://github.com/gin-gonic/gin/pull/2196)
- Update validator to v10 [#2190](https://github.com/gin-gonic/gin/pull/2190)
- upgrade go-validator to v10 for README [#2189](https://github.com/gin-gonic/gin/pull/2189)
- Update to currently output [#2188](https://github.com/gin-gonic/gin/pull/2188)
- Fix "Custom Validators" example [#2186](https://github.com/gin-gonic/gin/pull/2186)
- Add project to README [#2165](https://github.com/gin-gonic/gin/pull/2165)
- docs(benchmarks): for gin v1.5 [#2153](https://github.com/gin-gonic/gin/pull/2153)
- Changed wording for clarity in README.md [#2122](https://github.com/gin-gonic/gin/pull/2122)

### MISC

- ci support go1.14 [#2262](https://github.com/gin-gonic/gin/pull/2262)
- chore: upgrade depend version [#2231](https://github.com/gin-gonic/gin/pull/2231)
- Drop support go1.10 [#2147](https://github.com/gin-gonic/gin/pull/2147)
- fix comment in `mode.go` [#2129](https://github.com/gin-gonic/gin/pull/2129)

## Gin v1.5.0

- [FIX] Use DefaultWriter and DefaultErrorWriter for debug messages [#1891](https://github.com/gin-gonic/gin/pull/1891)
- [NEW] Now you can parse the inline lowercase start structure [#1893](https://github.com/gin-gonic/gin/pull/1893)
- [FIX] Some code improvements [#1909](https://github.com/gin-gonic/gin/pull/1909)
- [FIX] Use encode replace json marshal increase json encoder speed [#1546](https://github.com/gin-gonic/gin/pull/1546)
- [NEW] Hold matched route full path in the Context [#1826](https://github.com/gin-gonic/gin/pull/1826)
- [FIX] Fix context.Params race condition on Copy() [#1841](https://github.com/gin-gonic/gin/pull/1841)
- [NEW] Add context param query cache [#1450](https://github.com/gin-gonic/gin/pull/1450)
- [FIX] Improve GetQueryMap performance [#1918](https://github.com/gin-gonic/gin/pull/1918)
- [FIX] Improve get post data [#1920](https://github.com/gin-gonic/gin/pull/1920)
- [FIX] Use context instead of x/net/context [#1922](https://github.com/gin-gonic/gin/pull/1922)
- [FIX] Attempt to fix PostForm cache bug [#1931](https://github.com/gin-gonic/gin/pull/1931)
- [NEW] Add support of multipart multi files [#1949](https://github.com/gin-gonic/gin/pull/1949)
- [NEW] Support bind http header param [#1957](https://github.com/gin-gonic/gin/pull/1957)
- [FIX] Drop support for go1.8 and go1.9 [#1933](https://github.com/gin-gonic/gin/pull/1933)
- [FIX] Bugfix for the FullPath feature [#1919](https://github.com/gin-gonic/gin/pull/1919)
- [FIX] Gin1.5 bytes.Buffer to strings.Builder [#1939](https://github.com/gin-gonic/gin/pull/1939)
- [FIX] Upgrade github.com/ugorji/go/codec [#1969](https://github.com/gin-gonic/gin/pull/1969)
- [NEW] Support bind unix time [#1980](https://github.com/gin-gonic/gin/pull/1980)
- [FIX] Simplify code [#2004](https://github.com/gin-gonic/gin/pull/2004)
- [NEW] Support negative Content-Length in DataFromReader [#1981](https://github.com/gin-gonic/gin/pull/1981)
- [FIX] Identify terminal on a RISC-V architecture for auto-colored logs [#2019](https://github.com/gin-gonic/gin/pull/2019)
- [BREAKING] `Context.JSONP()` now expects a semicolon (`;`) at the end [#2007](https://github.com/gin-gonic/gin/pull/2007)
- [BREAKING] Upgrade default `binding.Validator` to v9 (see [its changelog](https://github.com/go-playground/validator/releases/tag/v9.0.0)) [#1015](https://github.com/gin-gonic/gin/pull/1015)
- [NEW] Add `DisallowUnknownFields()` in `Context.BindJSON()` [#2028](https://github.com/gin-gonic/gin/pull/2028)
- [NEW] Use specific `net.Listener` with `Engine.RunListener()` [#2023](https://github.com/gin-gonic/gin/pull/2023)
- [FIX] Fix some typo [#2079](https://github.com/gin-gonic/gin/pull/2079) [#2080](https://github.com/gin-gonic/gin/pull/2080)
- [FIX] Relocate binding body tests [#2086](https://github.com/gin-gonic/gin/pull/2086)
- [FIX] Use Writer in Context.Status [#1606](https://github.com/gin-gonic/gin/pull/1606)
- [FIX] `Engine.RunUnix()` now returns the error if it can't change the file mode [#2093](https://github.com/gin-gonic/gin/pull/2093)
- [FIX] `RouterGroup.StaticFS()` leaked files. Now it closes them. [#2118](https://github.com/gin-gonic/gin/pull/2118)
- [FIX] `Context.Request.FormFile` leaked file. Now it closes it. [#2114](https://github.com/gin-gonic/gin/pull/2114)
- [FIX] Ignore walking on `form:"-"` mapping [#1943](https://github.com/gin-gonic/gin/pull/1943)

### Gin v1.4.0

- [NEW] Support for [Go Modules](https://github.com/golang/go/wiki/Modules) [#1569](https://github.com/gin-gonic/gin/pull/1569)
- [NEW] Refactor of form mapping multipart request [#1829](https://github.com/gin-gonic/gin/pull/1829)
- [FIX] Truncate Latency precision in long running request [#1830](https://github.com/gin-gonic/gin/pull/1830)
- [FIX] IsTerm flag should not be affected by DisableConsoleColor method. [#1802](https://github.com/gin-gonic/gin/pull/1802)
- [NEW] Supporting file binding [#1264](https://github.com/gin-gonic/gin/pull/1264)
- [NEW] Add support for mapping arrays [#1797](https://github.com/gin-gonic/gin/pull/1797)
- [FIX] Readme updates [#1793](https://github.com/gin-gonic/gin/pull/1793) [#1788](https://github.com/gin-gonic/gin/pull/1788) [1789](https://github.com/gin-gonic/gin/pull/1789)
- [FIX] StaticFS: Fixed Logging two log lines on 404. [#1805](https://github.com/gin-gonic/gin/pull/1805), [#1804](https://github.com/gin-gonic/gin/pull/1804)
- [NEW] Make context.Keys available as LogFormatterParams [#1779](https://github.com/gin-gonic/gin/pull/1779)
- [NEW] Use internal/json for Marshal/Unmarshal [#1791](https://github.com/gin-gonic/gin/pull/1791)
- [NEW] Support mapping time.Duration [#1794](https://github.com/gin-gonic/gin/pull/1794)
- [NEW] Refactor form mappings [#1749](https://github.com/gin-gonic/gin/pull/1749)
- [NEW] Added flag to context.Stream indicates if client disconnected in middle of stream [#1252](https://github.com/gin-gonic/gin/pull/1252)
- [FIX] Moved [examples](https://github.com/gin-gonic/examples) to stand alone Repo [#1775](https://github.com/gin-gonic/gin/pull/1775)
- [NEW] Extend context.File to allow for the content-disposition attachments via a new method context.Attachment [#1260](https://github.com/gin-gonic/gin/pull/1260)
- [FIX] Support HTTP content negotiation wildcards [#1112](https://github.com/gin-gonic/gin/pull/1112)
- [NEW] Add prefix from X-Forwarded-Prefix in redirectTrailingSlash [#1238](https://github.com/gin-gonic/gin/pull/1238)
- [FIX] context.Copy() race condition [#1020](https://github.com/gin-gonic/gin/pull/1020)
- [NEW] Add context.HandlerNames() [#1729](https://github.com/gin-gonic/gin/pull/1729)
- [FIX] Change color methods to public in the defaultLogger. [#1771](https://github.com/gin-gonic/gin/pull/1771)
- [FIX] Update writeHeaders method to use http.Header.Set [#1722](https://github.com/gin-gonic/gin/pull/1722)
- [NEW] Add response size to LogFormatterParams [#1752](https://github.com/gin-gonic/gin/pull/1752)
- [NEW] Allow ignoring field on form mapping [#1733](https://github.com/gin-gonic/gin/pull/1733)
- [NEW] Add a function to force color in console output. [#1724](https://github.com/gin-gonic/gin/pull/1724)
- [FIX] Context.Next() - recheck len of handlers on every iteration. [#1745](https://github.com/gin-gonic/gin/pull/1745)
- [FIX] Fix all errcheck warnings [#1739](https://github.com/gin-gonic/gin/pull/1739) [#1653](https://github.com/gin-gonic/gin/pull/1653)
- [NEW] context: inherits context cancellation and deadline from http.Request context for Go>=1.7 [#1690](https://github.com/gin-gonic/gin/pull/1690)
- [NEW] Binding for URL Params [#1694](https://github.com/gin-gonic/gin/pull/1694)
- [NEW] Add LoggerWithFormatter method [#1677](https://github.com/gin-gonic/gin/pull/1677)
- [FIX] CI testing updates [#1671](https://github.com/gin-gonic/gin/pull/1671) [#1670](https://github.com/gin-gonic/gin/pull/1670) [#1682](https://github.com/gin-gonic/gin/pull/1682) [#1669](https://github.com/gin-gonic/gin/pull/1669)
- [FIX] StaticFS(): Send 404 when path does not exist [#1663](https://github.com/gin-gonic/gin/pull/1663)
- [FIX] Handle nil body for JSON binding [#1638](https://github.com/gin-gonic/gin/pull/1638)
- [FIX] Support bind uri param [#1612](https://github.com/gin-gonic/gin/pull/1612)
- [FIX] recovery: fix issue with syscall import on google app engine [#1640](https://github.com/gin-gonic/gin/pull/1640)
- [FIX] Make sure the debug log contains line breaks [#1650](https://github.com/gin-gonic/gin/pull/1650)
- [FIX] Panic stack trace being printed during recovery of broken pipe [#1089](https://github.com/gin-gonic/gin/pull/1089) [#1259](https://github.com/gin-gonic/gin/pull/1259)
- [NEW] RunFd method to run http.Server through a file descriptor [#1609](https://github.com/gin-gonic/gin/pull/1609)
- [NEW] Yaml binding support [#1618](https://github.com/gin-gonic/gin/pull/1618)
- [FIX] Pass MaxMultipartMemory when FormFile is called [#1600](https://github.com/gin-gonic/gin/pull/1600)
- [FIX] LoadHTML\* tests [#1559](https://github.com/gin-gonic/gin/pull/1559)
- [FIX] Removed use of sync.pool from HandleContext [#1565](https://github.com/gin-gonic/gin/pull/1565)
- [FIX] Format output log to os.Stderr [#1571](https://github.com/gin-gonic/gin/pull/1571)
- [FIX] Make logger use a yellow background and a darkgray text for legibility [#1570](https://github.com/gin-gonic/gin/pull/1570)
- [FIX] Remove sensitive request information from panic log. [#1370](https://github.com/gin-gonic/gin/pull/1370)
- [FIX] log.Println() does not print timestamp [#829](https://github.com/gin-gonic/gin/pull/829) [#1560](https://github.com/gin-gonic/gin/pull/1560)
- [NEW] Add PureJSON renderer [#694](https://github.com/gin-gonic/gin/pull/694)
- [FIX] Add missing copyright and update if/else [#1497](https://github.com/gin-gonic/gin/pull/1497)
- [FIX] Update msgpack usage [#1498](https://github.com/gin-gonic/gin/pull/1498)
- [FIX] Use protobuf on render [#1496](https://github.com/gin-gonic/gin/pull/1496)
- [FIX] Add support for Protobuf format response [#1479](https://github.com/gin-gonic/gin/pull/1479)
- [NEW] Set default time format in form binding [#1487](https://github.com/gin-gonic/gin/pull/1487)
- [FIX] Add BindXML and ShouldBindXML [#1485](https://github.com/gin-gonic/gin/pull/1485)
- [NEW] Upgrade dependency libraries [#1491](https://github.com/gin-gonic/gin/pull/1491)

## Gin v1.3.0

- [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383)
- [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358)
- [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273)
- [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304)
- [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341)
- [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336)
- [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333)
- [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138)
- [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277)
- [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047)
- [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117)
- [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029)
- [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026)
- [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999)
- [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993)
- [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie)
- [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072)
- [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250)
- [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460)

## Gin 1.2.0

- [NEW] Switch from godeps to govendor
- [NEW] Add support for Let's Encrypt via gin-gonic/autotls
- [NEW] Improve README examples and add extra at examples folder
- [NEW] Improved support with App Engine
- [NEW] Add custom template delimiters, see #860
- [NEW] Add Template Func Maps, see #962
- [NEW] Add \*context.Handler(), see #928
- [NEW] Add \*context.GetRawData()
- [NEW] Add \*context.GetHeader() (request)
- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type)
- [NEW] Add \*context.Keys type cast helpers
- [NEW] Add \*context.ShouldBindWith()
- [NEW] Add \*context.MustBindWith()
- [NEW] Add \*engine.SetFuncMap()
- [DEPRECATE] On next release: \*context.BindWith(), see #855
- [FIX] Refactor render
- [FIX] Reworked tests
- [FIX] logger now supports cygwin
- [FIX] Use X-Forwarded-For before X-Real-IP
- [FIX] time.Time binding (#904)

## Gin 1.1.4

- [NEW] Support google appengine for IsTerminal func

## Gin 1.1.3

- [FIX] Reverted Logger: skip ANSI color commands

## Gin 1.1

- [NEW] Implement QueryArray and PostArray methods
- [NEW] Refactor GetQuery and GetPostForm
- [NEW] Add contribution guide
- [FIX] Corrected typos in README
- [FIX] Removed additional Iota
- [FIX] Changed imports to gopkg instead of github in README (#733)
- [FIX] Logger: skip ANSI color commands if output is not a tty

## Gin 1.0rc2 (...)

- [PERFORMANCE] Fast path for writing Content-Type.
- [PERFORMANCE] Much faster 404 routing
- [PERFORMANCE] Allocation optimizations
- [PERFORMANCE] Faster root tree lookup
- [PERFORMANCE] Zero overhead, String() and JSON() rendering.
- [PERFORMANCE] Faster ClientIP parsing
- [PERFORMANCE] Much faster SSE implementation
- [NEW] Benchmarks suite
- [NEW] Bind validation can be disabled and replaced with custom validators.
- [NEW] More flexible HTML render
- [NEW] Multipart and PostForm bindings
- [NEW] Adds method to return all the registered routes
- [NEW] Context.HandlerName() returns the main handler's name
- [NEW] Adds Error.IsType() helper
- [FIX] Binding multipart form
- [FIX] Integration tests
- [FIX] Crash when binding non struct object in Context.
- [FIX] RunTLS() implementation
- [FIX] Logger() unit tests
- [FIX] Adds SetHTMLTemplate() warning
- [FIX] Context.IsAborted()
- [FIX] More unit tests
- [FIX] JSON, XML, HTML renders accept custom content-types
- [FIX] gin.AbortIndex is unexported
- [FIX] Better approach to avoid directory listing in StaticFS()
- [FIX] Context.ClientIP() always returns the IP with trimmed spaces.
- [FIX] Better warning when running in debug mode.
- [FIX] Google App Engine integration. debugPrint does not use os.Stdout
- [FIX] Fixes integer overflow in error type
- [FIX] Error implements the json.Marshaller interface
- [FIX] MIT license in every file

## Gin 1.0rc1 (May 22, 2015)

- [PERFORMANCE] Zero allocation router
- [PERFORMANCE] Faster JSON, XML and text rendering
- [PERFORMANCE] Custom hand optimized HttpRouter for Gin
- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations
- [NEW] Built-in support for golang.org/x/net/context
- [NEW] Any(path, handler). Create a route that matches any path
- [NEW] Refactored rendering pipeline (faster and static typed)
- [NEW] Refactored errors API
- [NEW] IndentedJSON() prints pretty JSON
- [NEW] Added gin.DefaultWriter
- [NEW] UNIX socket support
- [NEW] RouterGroup.BasePath is exposed
- [NEW] JSON validation using go-validate-yourself (very powerful options)
- [NEW] Completed suite of unit tests
- [NEW] HTTP streaming with c.Stream()
- [NEW] StaticFile() creates a router for serving just one file.
- [NEW] StaticFS() has an option to disable directory listing.
- [NEW] StaticFS() for serving static files through virtual filesystems
- [NEW] Server-Sent Events native support
- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler
- [NEW] Added LoggerWithWriter() middleware
- [NEW] Added RecoveryWithWriter() middleware
- [NEW] Added DefaultPostFormValue()
- [NEW] Added DefaultFormValue()
- [NEW] Added DefaultParamValue()
- [FIX] BasicAuth() when using custom realm
- [FIX] Bug when serving static files in nested routing group
- [FIX] Redirect using built-in http.Redirect()
- [FIX] Logger when printing the requested path
- [FIX] Documentation typos
- [FIX] Context.Engine renamed to Context.engine
- [FIX] Better debugging messages
- [FIX] ErrorLogger
- [FIX] Debug HTTP render
- [FIX] Refactored binding and render modules
- [FIX] Refactored Context initialization
- [FIX] Refactored BasicAuth()
- [FIX] NoMethod/NoRoute handlers
- [FIX] Hijacking http
- [FIX] Better support for Google App Engine (using log instead of fmt)

## Gin 0.6 (Mar 9, 2015)

- [NEW] Support multipart/form-data
- [NEW] NoMethod handler
- [NEW] Validate sub structures
- [NEW] Support for HTTP Realm Auth
- [FIX] Unsigned integers in binding
- [FIX] Improve color logger

## Gin 0.5 (Feb 7, 2015)

- [NEW] Content Negotiation
- [FIX] Solved security bug that allow a client to spoof ip
- [FIX] Fix unexported/ignored fields in binding

## Gin 0.4 (Aug 21, 2014)

- [NEW] Development mode
- [NEW] Unit tests
- [NEW] Add Content.Redirect()
- [FIX] Deferring WriteHeader()
- [FIX] Improved documentation for model binding

## Gin 0.3 (Jul 18, 2014)

- [PERFORMANCE] Normal log and error log are printed in the same call.
- [PERFORMANCE] Improve performance of NoRouter()
- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults.
- [NEW] Flexible rendering API
- [NEW] Add Context.File()
- [NEW] Add shortcut RunTLS() for http.ListenAndServeTLS
- [FIX] Rename NotFound404() to NoRoute()
- [FIX] Errors in context are purged
- [FIX] Adds HEAD method in Static file serving
- [FIX] Refactors Static() file serving
- [FIX] Using keyed initialization to fix app-engine integration
- [FIX] Can't unmarshal JSON array, #63
- [FIX] Renaming Context.Req to Context.Request
- [FIX] Check application/x-www-form-urlencoded when parsing form

## Gin 0.2b (Jul 08, 2014)

- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead
- [NEW] Travis CI integration
- [NEW] Completely new logger
- [NEW] New API for serving static files. gin.Static()
- [NEW] gin.H() can be serialized into XML
- [NEW] Typed errors. Errors can be typed. Internet/external/custom.
- [NEW] Support for Godeps
- [NEW] Travis/Godocs badges in README
- [NEW] New Bind() and BindWith() methods for parsing request body.
- [NEW] Add Content.Copy()
- [NEW] Add context.LastError()
- [NEW] Add shortcut for OPTIONS HTTP method
- [FIX] Tons of README fixes
- [FIX] Header is written before body
- [FIX] BasicAuth() and changes API a little bit
- [FIX] Recovery() middleware only prints panics
- [FIX] Context.Get() does not panic anymore. Use MustGet() instead.
- [FIX] Multiple http.WriteHeader() in NotFound handlers
- [FIX] Engine.Run() panics if http server can't be set up
- [FIX] Crash when route path doesn't start with '/'
- [FIX] Do not update header when status code is negative
- [FIX] Setting response headers before calling WriteHeader in context.String()
- [FIX] Add MIT license
- [FIX] Changes behaviour of ErrorLogger() and Logger()


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

We welcome both issue reports and pull requests! Please follow these guidelines to help maintainers respond effectively.

## Issues

- **Before opening a new issue:**
  - Use the search tool to check for existing issues or feature requests.
  - Review existing issues and provide feedback or react to them.
  - Use English for all communications — it is the language all maintainers read and write.
  - For questions, configuration or deployment problems, please use the [Discussions Forum](https://github.com/gin-gonic/gin/discussions).
  - For bug reports involving sensitive security issues, email <appleboy.tw@gmail.com> instead of posting publicly.

- **Reporting a bug:**
  - Please provide a clear description of your issue, and a minimal reproducible code example if possible.
  - Include the Gin version (or commit reference), Go version, and operating system.
  - Indicate whether you can reproduce the bug and describe steps to do so.
  - Attach relevant logs per [Logging Documentation](https://docs.gitea.com/administration/logging-config#collecting-logs-for-help).

- **Feature requests:**
  - Before opening a request, check that a similar idea hasn’t already been suggested.
  - Clearly describe your proposed feature and its benefits.

_For API Documentation, User Guides, and more, see:_

- [Go.dev API Documentation](https://pkg.go.dev/github.com/gin-gonic/gin)
- [Gin User Guides](https://gin-gonic.com/)
- [Discussions Forum](https://github.com/gin-gonic/gin/discussions)

## Pull Requests

Please ensure your pull request meets the following requirements:

- Open your pull request against the `master` branch.
- Your pull request should have no more than two commits — squash them if necessary.
- All tests pass in available continuous integration systems (e.g., GitHub Actions).
- Add or modify tests to cover your code changes.
- If your pull request introduces a new feature, document it in [`docs/doc.md`](docs/doc.md), not in the README.
- Follow the checklist in the [Pull Request Template](.github/PULL_REQUEST_TEMPLATE.md).

Thank you for contributing!


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2014-present Manuel Martínez-Almeida

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: Makefile
================================================
GO ?= go
GOFMT ?= gofmt "-s"
GO_VERSION=$(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
PACKAGES ?= $(shell $(GO) list ./...)
VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /examples/)
GOFILES := $(shell find . -name "*.go")
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|ginS$$|binding$$|render$$' | grep -v examples)
TESTTAGS ?= ""

.PHONY: test
# Run tests to verify code functionality.
test:
	echo "mode: count" > coverage.out
	for d in $(TESTFOLDER); do \
		if [ -n "$(TESTTAGS)" ]; then \
			$(GO) test $(TESTTAGS) -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \
		else \
			$(GO) test -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \
		fi; \
		cat tmp.out; \
		if grep -q "^--- FAIL" tmp.out; then \
			rm tmp.out; \
			exit 1; \
		elif grep -q "build failed" tmp.out; then \
			rm tmp.out; \
			exit 1; \
		elif grep -q "setup failed" tmp.out; then \
			rm tmp.out; \
			exit 1; \
		fi; \
		if [ -f profile.out ]; then \
			cat profile.out | grep -v "mode:" >> coverage.out; \
			rm profile.out; \
		fi; \
	done

.PHONY: fmt
# Ensure consistent code formatting.
fmt:
	$(GOFMT) -w $(GOFILES)

.PHONY: fmt-check
# format (check only).
fmt-check:
	@diff=$$($(GOFMT) -d $(GOFILES)); \
	if [ -n "$$diff" ]; then \
		echo "Please run 'make fmt' and commit the result:"; \
		echo "$${diff}"; \
		exit 1; \
	fi;

.PHONY: vet
# Examine packages and report suspicious constructs if any.
vet:
	$(GO) vet $(VETPACKAGES)

.PHONY: lint
# Inspect source code for stylistic errors or potential bugs.
lint:
	@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
		$(GO) get -u golang.org/x/lint/golint; \
	fi
	for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;

.PHONY: misspell
# Correct commonly misspelled English words in source code.
misspell:
	@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
		$(GO) get -u github.com/client9/misspell/cmd/misspell; \
	fi
	misspell -w $(GOFILES)

.PHONY: misspell-check
# misspell (check only).
misspell-check:
	@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
		$(GO) get -u github.com/client9/misspell/cmd/misspell; \
	fi
	misspell -error $(GOFILES)

.PHONY: tools
# Install tools (golint and misspell).
tools:
	@if [ $(GO_VERSION) -gt 15 ]; then \
		$(GO) install golang.org/x/lint/golint@latest; \
		$(GO) install github.com/client9/misspell/cmd/misspell@latest; \
	elif [ $(GO_VERSION) -lt 16 ]; then \
		$(GO) install golang.org/x/lint/golint; \
		$(GO) install github.com/client9/misspell/cmd/misspell; \
	fi

.PHONY: help
# Help.
help:
	@echo ''
	@echo 'Usage:'
	@echo ' make [target]'
	@echo ''
	@echo 'Targets:'
	@awk '/^[a-zA-Z\-\0-9]+:/ { \
	helpMessage = match(lastLine, /^# (.*)/); \
		if (helpMessage) { \
			helpCommand = substr($$1, 0, index($$1, ":")-1); \
			helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \
			printf " - \033[36m%-20s\033[0m %s\n", helpCommand, helpMessage; \
		} \
	} \
	{ lastLine = $$0 }' $(MAKEFILE_LIST)

.DEFAULT_GOAL := help


================================================
FILE: README.md
================================================
# Gin Web Framework

<img align="right" width="159px" src="https://raw.githubusercontent.com/gin-gonic/logo/master/color.png">

[![Build Status](https://github.com/gin-gonic/gin/actions/workflows/gin.yml/badge.svg?branch=master)](https://github.com/gin-gonic/gin/actions/workflows/gin.yml)
[![Trivy Security Scan](https://github.com/gin-gonic/gin/actions/workflows/trivy-scan.yml/badge.svg)](https://github.com/gin-gonic/gin/actions/workflows/trivy-scan.yml)
[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
[![Go Reference](https://pkg.go.dev/badge/github.com/gin-gonic/gin?status.svg)](https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc)
[![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge)
[![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin)
[![Release](https://img.shields.io/github/release/gin-gonic/gin.svg?style=flat-square)](https://github.com/gin-gonic/gin/releases)

## 📰 Gin 1.12.0 is now available!

We're excited to announce the release of **[Gin 1.12.0](https://gin-gonic.com/en/blog/news/gin-1-12-0-release-announcement/)**! This release brings new features, performance improvements, and important bug fixes. Check out the [release announcement](https://gin-gonic.com/en/blog/news/gin-1-12-0-release-announcement/) on our official blog for the full details.

---

Gin is a high-performance HTTP web framework written in [Go](https://go.dev/). It provides a Martini-like API but with significantly better performance—up to 40 times faster—thanks to [httprouter](https://github.com/julienschmidt/httprouter). Gin is designed for building REST APIs, web applications, and microservices where speed and developer productivity are essential.

**Why choose Gin?**

Gin combines the simplicity of Express.js-style routing with Go's performance characteristics, making it ideal for:

- Building high-throughput REST APIs
- Developing microservices that need to handle many concurrent requests
- Creating web applications that require fast response times
- Prototyping web services quickly with minimal boilerplate

**Gin's key features:**

- **Zero allocation router** - Extremely memory-efficient routing with no heap allocations
- **High performance** - Benchmarks show superior speed compared to other Go web frameworks
- **Middleware support** - Extensible middleware system for authentication, logging, CORS, etc.
- **Crash-free** - Built-in recovery middleware prevents panics from crashing your server
- **JSON validation** - Automatic request/response JSON binding and validation
- **Route grouping** - Organize related routes and apply common middleware
- **Error management** - Centralized error handling and logging
- **Built-in rendering** - Support for JSON, XML, HTML templates, and more
- **Extensible** - Large ecosystem of community middleware and plugins

## Getting Started

### Prerequisites

- **Go version**: Gin requires [Go](https://go.dev/) version [1.25](https://go.dev/doc/devel/release#go1.25.0) or above
- **Basic Go knowledge**: Familiarity with Go syntax and package management is helpful

### Installation

With [Go's module support](https://go.dev/wiki/Modules#how-to-use-modules), simply import Gin in your code and Go will automatically fetch it during build:

```go
import "github.com/gin-gonic/gin"
```

### Your First Gin Application

Here's a complete example that demonstrates Gin's simplicity:

```go
package main

import (
  "log"
  "net/http"

  "github.com/gin-gonic/gin"
)

func main() {
  // Create a Gin router with default middleware (logger and recovery)
  r := gin.Default()

  // Define a simple GET endpoint
  r.GET("/ping", func(c *gin.Context) {
    // Return JSON response
    c.JSON(http.StatusOK, gin.H{
      "message": "pong",
    })
  })

  // Start server on port 8080 (default)
  // Server will listen on 0.0.0.0:8080 (localhost:8080 on Windows)
  if err := r.Run(); err != nil {
    log.Fatalf("failed to run server: %v", err)
  }
}
```

**Running the application:**

1. Save the code above as `main.go`
2. Run the application:

   ```sh
   go run main.go
   ```

3. Open your browser and visit [`http://localhost:8080/ping`](http://localhost:8080/ping)
4. You should see: `{"message":"pong"}`

**What this example demonstrates:**

- Creating a Gin router with default middleware
- Defining HTTP endpoints with simple handler functions
- Returning JSON responses
- Starting an HTTP server

### Next Steps

After running your first Gin application, explore these resources to learn more:

#### 📚 Learning Resources

- **[Gin Quick Start Guide](docs/doc.md)** - Comprehensive tutorial with API examples and build configurations
- **[Example Repository](https://github.com/gin-gonic/examples)** - Ready-to-run examples demonstrating various Gin use cases:
  - REST API development
  - Authentication & middleware
  - File uploads and downloads
  - WebSocket connections
  - Template rendering

## 📖 Documentation

### API Reference

- **[Go.dev API Documentation](https://pkg.go.dev/github.com/gin-gonic/gin)** - Complete API reference with examples

### User Guides

The comprehensive documentation is available on [gin-gonic.com](https://gin-gonic.com) in multiple languages:

- [English](https://gin-gonic.com/en/docs/) | [简体中文](https://gin-gonic.com/zh-cn/docs/) | [繁體中文](https://gin-gonic.com/zh-tw/docs/)
- [日本語](https://gin-gonic.com/ja/docs/) | [한국어](https://gin-gonic.com/ko-kr/docs/) | [Español](https://gin-gonic.com/es/docs/)
- [Turkish](https://gin-gonic.com/tr/docs/) | [Persian](https://gin-gonic.com/fa/docs/) | [Português](https://gin-gonic.com/pt/docs/)
- [Russian](https://gin-gonic.com/ru/docs/) | [Indonesian](https://gin-gonic.com/id/docs/)

### Official Tutorials

- [Go.dev Tutorial: Developing a RESTful API with Go and Gin](https://go.dev/doc/tutorial/web-service-gin)

## ⚡ Performance Benchmarks

Gin demonstrates exceptional performance compared to other Go web frameworks. It uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter) for maximum efficiency. [View detailed benchmarks →](/BENCHMARKS.md)

**Gin vs. Other Go Frameworks** (GitHub API routing benchmark):

| Benchmark name                 |       (1) |             (2) |          (3) |             (4) |
| ------------------------------ | --------: | --------------: | -----------: | --------------: |
| BenchmarkGin_GithubAll         | **43550** | **27364 ns/op** |   **0 B/op** | **0 allocs/op** |
| BenchmarkAce_GithubAll         |     40543 |     29670 ns/op |       0 B/op |     0 allocs/op |
| BenchmarkAero_GithubAll        |     57632 |     20648 ns/op |       0 B/op |     0 allocs/op |
| BenchmarkBear_GithubAll        |      9234 |    216179 ns/op |   86448 B/op |   943 allocs/op |
| BenchmarkBeego_GithubAll       |      7407 |    243496 ns/op |   71456 B/op |   609 allocs/op |
| BenchmarkBone_GithubAll        |       420 |   2922835 ns/op |  720160 B/op |  8620 allocs/op |
| BenchmarkChi_GithubAll         |      7620 |    238331 ns/op |   87696 B/op |   609 allocs/op |
| BenchmarkDenco_GithubAll       |     18355 |     64494 ns/op |   20224 B/op |   167 allocs/op |
| BenchmarkEcho_GithubAll        |     31251 |     38479 ns/op |       0 B/op |     0 allocs/op |
| BenchmarkGocraftWeb_GithubAll  |      4117 |    300062 ns/op |  131656 B/op |  1686 allocs/op |
| BenchmarkGoji_GithubAll        |      3274 |    416158 ns/op |   56112 B/op |   334 allocs/op |
| BenchmarkGojiv2_GithubAll      |      1402 |    870518 ns/op |  352720 B/op |  4321 allocs/op |
| BenchmarkGoJsonRest_GithubAll  |      2976 |    401507 ns/op |  134371 B/op |  2737 allocs/op |
| BenchmarkGoRestful_GithubAll   |       410 |   2913158 ns/op |  910144 B/op |  2938 allocs/op |
| BenchmarkGorillaMux_GithubAll  |       346 |   3384987 ns/op |  251650 B/op |  1994 allocs/op |
| BenchmarkGowwwRouter_GithubAll |     10000 |    143025 ns/op |   72144 B/op |   501 allocs/op |
| BenchmarkHttpRouter_GithubAll  |     55938 |     21360 ns/op |       0 B/op |     0 allocs/op |
| BenchmarkHttpTreeMux_GithubAll |     10000 |    153944 ns/op |   65856 B/op |   671 allocs/op |
| BenchmarkKocha_GithubAll       |     10000 |    106315 ns/op |   23304 B/op |   843 allocs/op |
| BenchmarkLARS_GithubAll        |     47779 |     25084 ns/op |       0 B/op |     0 allocs/op |
| BenchmarkMacaron_GithubAll     |      3266 |    371907 ns/op |  149409 B/op |  1624 allocs/op |
| BenchmarkMartini_GithubAll     |       331 |   3444706 ns/op |  226551 B/op |  2325 allocs/op |
| BenchmarkPat_GithubAll         |       273 |   4381818 ns/op | 1483152 B/op | 26963 allocs/op |
| BenchmarkPossum_GithubAll      |     10000 |    164367 ns/op |   84448 B/op |   609 allocs/op |
| BenchmarkR2router_GithubAll    |     10000 |    160220 ns/op |   77328 B/op |   979 allocs/op |
| BenchmarkRivet_GithubAll       |     14625 |     82453 ns/op |   16272 B/op |   167 allocs/op |
| BenchmarkTango_GithubAll       |      6255 |    279611 ns/op |   63826 B/op |  1618 allocs/op |
| BenchmarkTigerTonic_GithubAll  |      2008 |    687874 ns/op |  193856 B/op |  4474 allocs/op |
| BenchmarkTraffic_GithubAll     |       355 |   3478508 ns/op |  820744 B/op | 14114 allocs/op |
| BenchmarkVulcan_GithubAll      |      6885 |    193333 ns/op |   19894 B/op |   609 allocs/op |

- (1): Total Repetitions achieved in constant time, higher means more confident result
- (2): Single Repetition Duration (ns/op), lower is better
- (3): Heap Memory (B/op), lower is better
- (4): Average Allocations per Repetition (allocs/op), lower is better

## 🔌 Middleware Ecosystem

Gin has a rich ecosystem of middleware for common web development needs. Explore community-contributed middleware:

- **[gin-contrib](https://github.com/gin-contrib)** - Official middleware collection including:
  - Authentication (JWT, Basic Auth, Sessions)
  - CORS, Rate limiting, Compression
  - Logging, Metrics, Tracing
  - Static file serving, Template engines
- **[gin-gonic/contrib](https://github.com/gin-gonic/contrib)** - Additional community middleware

## 🏢 Production Usage

Gin powers many high-traffic applications and services in production:

- **[gorush](https://github.com/appleboy/gorush)** - High-performance push notification server
- **[fnproject](https://github.com/fnproject/fn)** - Container-native, serverless platform
- **[photoprism](https://github.com/photoprism/photoprism)** - AI-powered personal photo management
- **[lura](https://github.com/luraproject/lura)** - Ultra-performant API Gateway framework
- **[picfit](https://github.com/thoas/picfit)** - Real-time image processing server
- **[dkron](https://github.com/distribworks/dkron)** - Distributed job scheduling system

## 🤝 Contributing

Gin is the work of hundreds of contributors from around the world. We welcome and appreciate your contributions! See the full list of [contributors](https://github.com/gin-gonic/gin/graphs/contributors).

### How to Contribute

- 🐛 **Report bugs** - Help us identify and fix issues
- 💡 **Suggest features** - Share your ideas for improvements
- 📝 **Improve documentation** - Help make our docs clearer
- 🔧 **Submit code** - Fix bugs or implement new features
- 🧪 **Write tests** - Improve our test coverage

### Getting Started with Contributing

1. Check out our [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines
2. Join our community discussions and ask questions

**All contributions are valued and help make Gin better for everyone!**


================================================
FILE: auth.go
================================================
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"crypto/subtle"
	"encoding/base64"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin/internal/bytesconv"
)

// AuthUserKey is the cookie name for user credential in basic auth.
const AuthUserKey = "user"

// AuthProxyUserKey is the cookie name for proxy_user credential in basic auth for proxy.
const AuthProxyUserKey = "proxy_user"

// Accounts defines a key/value for user/pass list of authorized logins.
type Accounts map[string]string

type authPair struct {
	value string
	user  string
}

type authPairs []authPair

func (a authPairs) searchCredential(authValue string) (string, bool) {
	if authValue == "" {
		return "", false
	}
	for _, pair := range a {
		if subtle.ConstantTimeCompare(bytesconv.StringToBytes(pair.value), bytesconv.StringToBytes(authValue)) == 1 {
			return pair.user, true
		}
	}
	return "", false
}

// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
// the key is the user name and the value is the password, as well as the name of the Realm.
// If the realm is empty, "Authorization Required" will be used by default.
// (see http://tools.ietf.org/html/rfc2617#section-1.2)
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
	if realm == "" {
		realm = "Authorization Required"
	}
	realm = "Basic realm=" + strconv.Quote(realm)
	pairs := processAccounts(accounts)
	return func(c *Context) {
		// Search user in the slice of allowed credentials
		user, found := pairs.searchCredential(c.requestHeader("Authorization"))
		if !found {
			// Credentials doesn't match, we return 401 and abort handlers chain.
			c.Header("WWW-Authenticate", realm)
			c.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		// The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using
		// c.MustGet(gin.AuthUserKey).
		c.Set(AuthUserKey, user)
	}
}

// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
// the key is the user name and the value is the password.
func BasicAuth(accounts Accounts) HandlerFunc {
	return BasicAuthForRealm(accounts, "")
}

func processAccounts(accounts Accounts) authPairs {
	length := len(accounts)
	assert1(length > 0, "Empty list of authorized credentials")
	pairs := make(authPairs, 0, length)
	for user, password := range accounts {
		assert1(user != "", "User can not be empty")
		value := authorizationHeader(user, password)
		pairs = append(pairs, authPair{
			value: value,
			user:  user,
		})
	}
	return pairs
}

func authorizationHeader(user, password string) string {
	base := user + ":" + password
	return "Basic " + base64.StdEncoding.EncodeToString(bytesconv.StringToBytes(base))
}

// BasicAuthForProxy returns a Basic HTTP Proxy-Authorization middleware.
// If the realm is empty, "Proxy Authorization Required" will be used by default.
func BasicAuthForProxy(accounts Accounts, realm string) HandlerFunc {
	if realm == "" {
		realm = "Proxy Authorization Required"
	}
	realm = "Basic realm=" + strconv.Quote(realm)
	pairs := processAccounts(accounts)
	return func(c *Context) {
		proxyUser, found := pairs.searchCredential(c.requestHeader("Proxy-Authorization"))
		if !found {
			// Credentials doesn't match, we return 407 and abort handlers chain.
			c.Header("Proxy-Authenticate", realm)
			c.AbortWithStatus(http.StatusProxyAuthRequired)
			return
		}
		// The proxy_user credentials was found, set proxy_user's id to key AuthProxyUserKey in this context, the proxy_user's id can be read later using
		// c.MustGet(gin.AuthProxyUserKey).
		c.Set(AuthProxyUserKey, proxyUser)
	}
}


================================================
FILE: auth_test.go
================================================
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"encoding/base64"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestBasicAuth(t *testing.T) {
	pairs := processAccounts(Accounts{
		"admin": "password",
		"foo":   "bar",
		"bar":   "foo",
	})

	assert.Len(t, pairs, 3)
	assert.Contains(t, pairs, authPair{
		user:  "bar",
		value: "Basic YmFyOmZvbw==",
	})
	assert.Contains(t, pairs, authPair{
		user:  "foo",
		value: "Basic Zm9vOmJhcg==",
	})
	assert.Contains(t, pairs, authPair{
		user:  "admin",
		value: "Basic YWRtaW46cGFzc3dvcmQ=",
	})
}

func TestBasicAuthFails(t *testing.T) {
	assert.Panics(t, func() { processAccounts(nil) })
	assert.Panics(t, func() {
		processAccounts(Accounts{
			"":    "password",
			"foo": "bar",
		})
	})
}

func TestBasicAuthSearchCredential(t *testing.T) {
	pairs := processAccounts(Accounts{
		"admin": "password",
		"foo":   "bar",
		"bar":   "foo",
	})

	user, found := pairs.searchCredential(authorizationHeader("admin", "password"))
	assert.Equal(t, "admin", user)
	assert.True(t, found)

	user, found = pairs.searchCredential(authorizationHeader("foo", "bar"))
	assert.Equal(t, "foo", user)
	assert.True(t, found)

	user, found = pairs.searchCredential(authorizationHeader("bar", "foo"))
	assert.Equal(t, "bar", user)
	assert.True(t, found)

	user, found = pairs.searchCredential(authorizationHeader("admins", "password"))
	assert.Empty(t, user)
	assert.False(t, found)

	user, found = pairs.searchCredential(authorizationHeader("foo", "bar "))
	assert.Empty(t, user)
	assert.False(t, found)

	user, found = pairs.searchCredential("")
	assert.Empty(t, user)
	assert.False(t, found)
}

func TestBasicAuthAuthorizationHeader(t *testing.T) {
	assert.Equal(t, "Basic YWRtaW46cGFzc3dvcmQ=", authorizationHeader("admin", "password"))
}

func TestBasicAuthSucceed(t *testing.T) {
	accounts := Accounts{"admin": "password"}
	router := New()
	router.Use(BasicAuth(accounts))
	router.GET("/login", func(c *Context) {
		c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
	})

	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/login", nil)
	req.Header.Set("Authorization", authorizationHeader("admin", "password"))
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.Equal(t, "admin", w.Body.String())
}

func TestBasicAuth401(t *testing.T) {
	called := false
	accounts := Accounts{"foo": "bar"}
	router := New()
	router.Use(BasicAuth(accounts))
	router.GET("/login", func(c *Context) {
		called = true
		c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
	})

	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/login", nil)
	req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
	router.ServeHTTP(w, req)

	assert.False(t, called)
	assert.Equal(t, http.StatusUnauthorized, w.Code)
	assert.Equal(t, "Basic realm=\"Authorization Required\"", w.Header().Get("WWW-Authenticate"))
}

func TestBasicAuth401WithCustomRealm(t *testing.T) {
	called := false
	accounts := Accounts{"foo": "bar"}
	router := New()
	router.Use(BasicAuthForRealm(accounts, "My Custom \"Realm\""))
	router.GET("/login", func(c *Context) {
		called = true
		c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
	})

	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/login", nil)
	req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
	router.ServeHTTP(w, req)

	assert.False(t, called)
	assert.Equal(t, http.StatusUnauthorized, w.Code)
	assert.Equal(t, "Basic realm=\"My Custom \\\"Realm\\\"\"", w.Header().Get("WWW-Authenticate"))
}

func TestBasicAuthForProxySucceed(t *testing.T) {
	accounts := Accounts{"admin": "password"}
	router := New()
	router.Use(BasicAuthForProxy(accounts, ""))
	router.Any("/*proxyPath", func(c *Context) {
		c.String(http.StatusOK, c.MustGet(AuthProxyUserKey).(string))
	})

	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/test", nil)
	req.Header.Set("Proxy-Authorization", authorizationHeader("admin", "password"))
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.Equal(t, "admin", w.Body.String())
}

func TestBasicAuthForProxy407(t *testing.T) {
	called := false
	accounts := Accounts{"foo": "bar"}
	router := New()
	router.Use(BasicAuthForProxy(accounts, ""))
	router.Any("/*proxyPath", func(c *Context) {
		called = true
		c.String(http.StatusOK, c.MustGet(AuthProxyUserKey).(string))
	})

	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/test", nil)
	req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
	router.ServeHTTP(w, req)

	assert.False(t, called)
	assert.Equal(t, http.StatusProxyAuthRequired, w.Code)
	assert.Equal(t, "Basic realm=\"Proxy Authorization Required\"", w.Header().Get("Proxy-Authenticate"))
}


================================================
FILE: benchmarks_test.go
================================================
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"html/template"
	"net/http"
	"os"
	"testing"
)

func BenchmarkOneRoute(B *testing.B) {
	router := New()
	router.GET("/ping", func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/ping")
}

func BenchmarkRecoveryMiddleware(B *testing.B) {
	router := New()
	router.Use(Recovery())
	router.GET("/", func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/")
}

func BenchmarkLoggerMiddleware(B *testing.B) {
	router := New()
	router.Use(LoggerWithWriter(newMockWriter()))
	router.GET("/", func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/")
}

func BenchmarkManyHandlers(B *testing.B) {
	router := New()
	router.Use(Recovery(), LoggerWithWriter(newMockWriter()))
	router.Use(func(c *Context) {})
	router.Use(func(c *Context) {})
	router.GET("/ping", func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/ping")
}

func Benchmark5Params(B *testing.B) {
	DefaultWriter = os.Stdout
	router := New()
	router.Use(func(c *Context) {})
	router.GET("/param/:param1/:params2/:param3/:param4/:param5", func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/param/path/to/parameter/john/12345")
}

func BenchmarkOneRouteJSON(B *testing.B) {
	router := New()
	data := struct {
		Status string `json:"status"`
	}{"ok"}
	router.GET("/json", func(c *Context) {
		c.JSON(http.StatusOK, data)
	})
	runRequest(B, router, http.MethodGet, "/json")
}

func BenchmarkOneRouteHTML(B *testing.B) {
	router := New()
	t := template.Must(template.New("index").Parse(`
		<html><body><h1>{{.}}</h1></body></html>`))
	router.SetHTMLTemplate(t)

	router.GET("/html", func(c *Context) {
		c.HTML(http.StatusOK, "index", "hola")
	})
	runRequest(B, router, http.MethodGet, "/html")
}

func BenchmarkOneRouteSet(B *testing.B) {
	router := New()
	router.GET("/ping", func(c *Context) {
		c.Set("key", "value")
	})
	runRequest(B, router, http.MethodGet, "/ping")
}

func BenchmarkOneRouteString(B *testing.B) {
	router := New()
	router.GET("/text", func(c *Context) {
		c.String(http.StatusOK, "this is a plain text")
	})
	runRequest(B, router, http.MethodGet, "/text")
}

func BenchmarkManyRoutesFirst(B *testing.B) {
	router := New()
	router.Any("/ping", func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/ping")
}

func BenchmarkManyRoutesLast(B *testing.B) {
	router := New()
	router.Any("/ping", func(c *Context) {})
	runRequest(B, router, "OPTIONS", "/ping")
}

func Benchmark404(B *testing.B) {
	router := New()
	router.Any("/something", func(c *Context) {})
	router.NoRoute(func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/ping")
}

func Benchmark404Many(B *testing.B) {
	router := New()
	router.GET("/", func(c *Context) {})
	router.GET("/path/to/something", func(c *Context) {})
	router.GET("/post/:id", func(c *Context) {})
	router.GET("/view/:id", func(c *Context) {})
	router.GET("/favicon.ico", func(c *Context) {})
	router.GET("/robots.txt", func(c *Context) {})
	router.GET("/delete/:id", func(c *Context) {})
	router.GET("/user/:id/:mode", func(c *Context) {})

	router.NoRoute(func(c *Context) {})
	runRequest(B, router, http.MethodGet, "/viewfake")
}

type mockWriter struct {
	headers http.Header
}

func newMockWriter() *mockWriter {
	return &mockWriter{
		http.Header{},
	}
}

func (m *mockWriter) Header() (h http.Header) {
	return m.headers
}

func (m *mockWriter) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func (m *mockWriter) WriteString(s string) (n int, err error) {
	return len(s), nil
}

func (m *mockWriter) WriteHeader(int) {}

func runRequest(B *testing.B, r *Engine, method, path string) {
	// create fake request
	req, err := http.NewRequest(method, path, nil)
	if err != nil {
		panic(err)
	}
	w := newMockWriter()
	B.ReportAllocs()
	B.ResetTimer()
	for B.Loop() {
		r.ServeHTTP(w, req)
	}
}


================================================
FILE: binding/binding.go
================================================
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

//go:build !nomsgpack

package binding

import "net/http"

// Content-Type MIME of the most common data formats.
const (
	MIMEJSON              = "application/json"
	MIMEHTML              = "text/html"
	MIMEXML               = "application/xml"
	MIMEXML2              = "text/xml"
	MIMEPlain             = "text/plain"
	MIMEPOSTForm          = "application/x-www-form-urlencoded"
	MIMEMultipartPOSTForm = "multipart/form-data"
	MIMEPROTOBUF          = "application/x-protobuf"
	MIMEMSGPACK           = "application/x-msgpack"
	MIMEMSGPACK2          = "application/msgpack"
	MIMEYAML              = "application/x-yaml"
	MIMEYAML2             = "application/yaml"
	MIMETOML              = "application/toml"
	MIMEBSON              = "application/bson"
)

// Binding describes the interface which needs to be implemented for binding the
// data present in the request such as JSON request body, query parameters or
// the form POST.
type Binding interface {
	Name() string
	Bind(*http.Request, any) error
}

// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
// but it reads the body from supplied bytes instead of req.Body.
type BindingBody interface {
	Binding
	BindBody([]byte, any) error
}

// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
// but it reads the Params.
type BindingUri interface {
	Name() string
	BindUri(map[string][]string, any) error
}

// StructValidator is the minimal interface which needs to be implemented in
// order for it to be used as the validator engine for ensuring the correctness
// of the request. Gin provides a default implementation for this using
// https://github.com/go-playground/validator/tree/v10.6.1.
type StructValidator interface {
	// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
	// If the received type is a slice|array, the validation should be performed travel on every element.
	// If the received type is not a struct or slice|array, any validation should be skipped and nil must be returned.
	// If the received type is a struct or pointer to a struct, the validation should be performed.
	// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
	// Otherwise nil must be returned.
	ValidateStruct(any) error

	// Engine returns the underlying validator engine which powers the
	// StructValidator implementation.
	Engine() any
}

// Validator is the default validator which implements the StructValidator
// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1
// under the hood.
var Validator StructValidator = &defaultValidator{}

// These implement the Binding interface and can be used to bind the data
// present in the request to struct instances.
var (
	JSON          BindingBody = jsonBinding{}
	XML           BindingBody = xmlBinding{}
	Form          Binding     = formBinding{}
	Query         Binding     = queryBinding{}
	FormPost      Binding     = formPostBinding{}
	FormMultipart Binding     = formMultipartBinding{}
	ProtoBuf      BindingBody = protobufBinding{}
	MsgPack       BindingBody = msgpackBinding{}
	YAML          BindingBody = yamlBinding{}
	Uri           BindingUri  = uriBinding{}
	Header        Binding     = headerBinding{}
	Plain         BindingBody = plainBinding{}
	TOML          BindingBody = tomlBinding{}
	BSON          BindingBody = bsonBinding{}
)

// Default returns the appropriate Binding instance based on the HTTP method
// and the content type.
func Default(method, contentType string) Binding {
	if method == http.MethodGet {
		return Form
	}

	switch contentType {
	case MIMEJSON:
		return JSON
	case MIMEXML, MIMEXML2:
		return XML
	case MIMEPROTOBUF:
		return ProtoBuf
	case MIMEMSGPACK, MIMEMSGPACK2:
		return MsgPack
	case MIMEYAML, MIMEYAML2:
		return YAML
	case MIMETOML:
		return TOML
	case MIMEMultipartPOSTForm:
		return FormMultipart
	case MIMEBSON:
		return BSON
	default: // case MIMEPOSTForm:
		return Form
	}
}

func validate(obj any) error {
	if Validator == nil {
		return nil
	}
	return Validator.ValidateStruct(obj)
}


================================================
FILE: binding/binding_msgpack_test.go
================================================
// Copyright 2020 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.

//go:build !nomsgpack

package binding

import (
	"bytes"
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/ugorji/go/codec"
)

func TestBindingMsgPack(t *testing.T) {
	test := FooStruct{
		Foo: "bar",
	}

	h := new(codec.MsgpackHandle)
	assert.NotNil(t, h)
	buf := bytes.NewBuffer([]byte{})
	assert.NotNil(t, buf)
	err := codec.NewEncoder(buf, h).Encode(test)
	require.NoError(t, err)

	data := buf.Bytes()

	testMsgPackBodyBinding(t,
		MsgPack, "msgpack",
		"/", "/",
		string(data), string(data[1:]))
}

func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	obj := FooStruct{}
	req := requestWithBody(http.MethodPost, path, body)
	req.Header.Add("Content-Type", MIMEMSGPACK)
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, "bar", obj.Foo)

	obj = FooStruct{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	req.Header.Add("Content-Type", MIMEMSGPACK)
	err = MsgPack.Bind(req, &obj)
	require.Error(t, err)
}

func TestBindingDefaultMsgPack(t *testing.T) {
	assert.Equal(t, MsgPack, Default(http.MethodPost, MIMEMSGPACK))
	assert.Equal(t, MsgPack, Default(http.MethodPut, MIMEMSGPACK2))
}


================================================
FILE: binding/binding_nomsgpack.go
================================================
// Copyright 2020 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.

//go:build nomsgpack

package binding

import "net/http"

// Content-Type MIME of the most common data formats.
const (
	MIMEJSON              = "application/json"
	MIMEHTML              = "text/html"
	MIMEXML               = "application/xml"
	MIMEXML2              = "text/xml"
	MIMEPlain             = "text/plain"
	MIMEPOSTForm          = "application/x-www-form-urlencoded"
	MIMEMultipartPOSTForm = "multipart/form-data"
	MIMEPROTOBUF          = "application/x-protobuf"
	MIMEYAML              = "application/x-yaml"
	MIMEYAML2             = "application/yaml"
	MIMETOML              = "application/toml"
	MIMEBSON              = "application/bson"
)

// Binding describes the interface which needs to be implemented for binding the
// data present in the request such as JSON request body, query parameters or
// the form POST.
type Binding interface {
	Name() string
	Bind(*http.Request, any) error
}

// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
// but it reads the body from supplied bytes instead of req.Body.
type BindingBody interface {
	Binding
	BindBody([]byte, any) error
}

// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
// but it reads the Params.
type BindingUri interface {
	Name() string
	BindUri(map[string][]string, any) error
}

// StructValidator is the minimal interface which needs to be implemented in
// order for it to be used as the validator engine for ensuring the correctness
// of the request. Gin provides a default implementation for this using
// https://github.com/go-playground/validator/tree/v10.6.1.
type StructValidator interface {
	// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
	// If the received type is not a struct, any validation should be skipped and nil must be returned.
	// If the received type is a struct or pointer to a struct, the validation should be performed.
	// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
	// Otherwise nil must be returned.
	ValidateStruct(any) error

	// Engine returns the underlying validator engine which powers the
	// StructValidator implementation.
	Engine() any
}

// Validator is the default validator which implements the StructValidator
// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1
// under the hood.
var Validator StructValidator = &defaultValidator{}

// These implement the Binding interface and can be used to bind the data
// present in the request to struct instances.
var (
	JSON          = jsonBinding{}
	XML           = xmlBinding{}
	Form          = formBinding{}
	Query         = queryBinding{}
	FormPost      = formPostBinding{}
	FormMultipart = formMultipartBinding{}
	ProtoBuf      = protobufBinding{}
	YAML          = yamlBinding{}
	Uri           = uriBinding{}
	Header        = headerBinding{}
	TOML          = tomlBinding{}
	Plain         = plainBinding{}
	BSON          BindingBody = bsonBinding{}
)

// Default returns the appropriate Binding instance based on the HTTP method
// and the content type.
func Default(method, contentType string) Binding {
	if method == "GET" {
		return Form
	}

	switch contentType {
	case MIMEJSON:
		return JSON
	case MIMEXML, MIMEXML2:
		return XML
	case MIMEPROTOBUF:
		return ProtoBuf
	case MIMEYAML, MIMEYAML2:
		return YAML
	case MIMEMultipartPOSTForm:
		return FormMultipart
	case MIMETOML:
		return TOML
	case MIMEBSON:
		return BSON
	default: // case MIMEPOSTForm:
		return Form
	}
}

func validate(obj any) error {
	if Validator == nil {
		return nil
	}
	return Validator.ValidateStruct(obj)
}


================================================
FILE: binding/binding_test.go
================================================
// Copyright 2014 Manu Martinez-Almeida. 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"
	"encoding/json"
	"errors"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"reflect"
	"strconv"
	"strings"
	"testing"
	"time"

	"github.com/gin-gonic/gin/testdata/protoexample"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.mongodb.org/mongo-driver/v2/bson"
	"google.golang.org/protobuf/proto"
)

type appkey struct {
	Appkey string `json:"appkey" form:"appkey"`
}

type QueryTest struct {
	Page int `json:"page" form:"page"`
	Size int `json:"size" form:"size"`
	appkey
}

type FooStruct struct {
	Foo string `msgpack:"foo" json:"foo" form:"foo" xml:"foo" binding:"required,max=32"`
}

type FooBarStruct struct {
	FooStruct
	Bar string `msgpack:"bar" json:"bar" form:"bar" xml:"bar" binding:"required"`
}

type FooBarFileStruct struct {
	FooBarStruct
	File *multipart.FileHeader `form:"file" binding:"required"`
}

type FooBarFileFailStruct struct {
	FooBarStruct
	File *multipart.FileHeader `invalid_name:"file" binding:"required"`
}

type FooDefaultBarStruct struct {
	FooStruct
	Bar string `msgpack:"bar" json:"bar" form:"bar,default=hello" xml:"bar" binding:"required"`
}

type FooStructUseNumber struct {
	Foo any `json:"foo" binding:"required"`
}

type FooStructDisallowUnknownFields struct {
	Foo any `json:"foo" binding:"required"`
}

type FooBarStructForTimeType struct {
	TimeFoo       time.Time `form:"time_foo" time_format:"2006-01-02" time_utc:"1" time_location:"Asia/Chongqing"`
	TimeBar       time.Time `form:"time_bar" time_format:"2006-01-02" time_utc:"1"`
	CreateTime    time.Time `form:"createTime" time_format:"unixNano"`
	UnixTime      time.Time `form:"unixTime" time_format:"unix"`
	UnixMilliTime time.Time `form:"unixMilliTime" time_format:"unixmilli"`
	UnixMicroTime time.Time `form:"unixMicroTime" time_format:"uNiXmiCrO"`
}

type FooStructForTimeTypeNotUnixFormat struct {
	CreateTime    time.Time `form:"createTime" time_format:"unixNano"`
	UnixTime      time.Time `form:"unixTime" time_format:"unix"`
	UnixMilliTime time.Time `form:"unixMilliTime" time_format:"unixMilli"`
	UnixMicroTime time.Time `form:"unixMicroTime" time_format:"unixMicro"`
}

type FooStructForTimeTypeNotFormat struct {
	TimeFoo time.Time `form:"time_foo"`
}

type FooStructForTimeTypeFailFormat struct {
	TimeFoo time.Time `form:"time_foo" time_format:"2017-11-15"`
}

type FooStructForTimeTypeFailLocation struct {
	TimeFoo time.Time `form:"time_foo" time_format:"2006-01-02" time_location:"/asia/chongqing"`
}

type FooStructForMapType struct {
	MapFoo map[string]any `form:"map_foo"`
}

type FooStructForIgnoreFormTag struct {
	Foo *string `form:"-"`
}

type InvalidNameType struct {
	TestName string `invalid_name:"test_name"`
}

type InvalidNameMapType struct {
	TestName struct {
		MapFoo map[string]any `form:"map_foo"`
	}
}

type FooStructForSliceType struct {
	SliceFoo []int `form:"slice_foo"`
}

type FooStructForStructType struct {
	StructFoo struct {
		Idx int `form:"idx"`
	}
}

type FooStructForStructPointerType struct {
	StructPointerFoo *struct {
		Name string `form:"name"`
	}
}

type FooStructForSliceMapType struct {
	// Unknown type: not support map
	SliceMapFoo []map[string]any `form:"slice_map_foo"`
}

type FooStructForBoolType struct {
	BoolFoo bool `form:"bool_foo"`
}

type FooStructForStringPtrType struct {
	PtrFoo *string `form:"ptr_foo"`
	PtrBar *string `form:"ptr_bar" binding:"required"`
}

type FooStructForMapPtrType struct {
	PtrBar *map[string]any `form:"ptr_bar"`
}

func TestBindingDefault(t *testing.T) {
	assert.Equal(t, Form, Default(http.MethodGet, ""))
	assert.Equal(t, Form, Default(http.MethodGet, MIMEJSON))

	assert.Equal(t, JSON, Default(http.MethodPost, MIMEJSON))
	assert.Equal(t, JSON, Default(http.MethodPut, MIMEJSON))

	assert.Equal(t, XML, Default(http.MethodPost, MIMEXML))
	assert.Equal(t, XML, Default(http.MethodPut, MIMEXML2))

	assert.Equal(t, Form, Default(http.MethodPost, MIMEPOSTForm))
	assert.Equal(t, Form, Default(http.MethodPut, MIMEPOSTForm))

	assert.Equal(t, FormMultipart, Default(http.MethodPost, MIMEMultipartPOSTForm))
	assert.Equal(t, FormMultipart, Default(http.MethodPut, MIMEMultipartPOSTForm))

	assert.Equal(t, ProtoBuf, Default(http.MethodPost, MIMEPROTOBUF))
	assert.Equal(t, ProtoBuf, Default(http.MethodPut, MIMEPROTOBUF))

	assert.Equal(t, YAML, Default(http.MethodPost, MIMEYAML))
	assert.Equal(t, YAML, Default(http.MethodPut, MIMEYAML))
	assert.Equal(t, YAML, Default(http.MethodPost, MIMEYAML2))
	assert.Equal(t, YAML, Default(http.MethodPut, MIMEYAML2))

	assert.Equal(t, TOML, Default(http.MethodPost, MIMETOML))
	assert.Equal(t, TOML, Default(http.MethodPut, MIMETOML))

	assert.Equal(t, BSON, Default(http.MethodPost, MIMEBSON))
	assert.Equal(t, BSON, Default(http.MethodPut, MIMEBSON))
}

func TestBindingJSONNilBody(t *testing.T) {
	var obj FooStruct
	req, _ := http.NewRequest(http.MethodPost, "/", nil)
	err := JSON.Bind(req, &obj)
	require.Error(t, err)
}

func TestBindingJSON(t *testing.T) {
	testBodyBinding(t,
		JSON, "json",
		"/", "/",
		`{"foo": "bar"}`, `{"bar": "foo"}`)
}

func TestBindingJSONSlice(t *testing.T) {
	EnableDecoderDisallowUnknownFields = true
	defer func() {
		EnableDecoderDisallowUnknownFields = false
	}()

	testBodyBindingSlice(t, JSON, "json", "/", "/", `[]`, ``)
	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{}]`)
	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"foo": ""}]`)
	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"foo": 123}]`)
	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"bar": 123}]`)
	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"foo": "123456789012345678901234567890123"}]`)
}

func TestBindingJSONUseNumber(t *testing.T) {
	testBodyBindingUseNumber(t,
		JSON, "json",
		"/", "/",
		`{"foo": 123}`, `{"bar": "foo"}`)
}

func TestBindingJSONUseNumber2(t *testing.T) {
	testBodyBindingUseNumber2(t,
		JSON, "json",
		"/", "/",
		`{"foo": 123}`, `{"bar": "foo"}`)
}

func TestBindingJSONDisallowUnknownFields(t *testing.T) {
	testBodyBindingDisallowUnknownFields(t, JSON,
		"/", "/",
		`{"foo": "bar"}`, `{"foo": "bar", "what": "this"}`)
}

func TestBindingJSONStringMap(t *testing.T) {
	testBodyBindingStringMap(t, JSON,
		"/", "/",
		`{"foo": "bar", "hello": "world"}`, `{"num": 2}`)
}

func TestBindingForm(t *testing.T) {
	testFormBinding(t, http.MethodPost,
		"/", "/",
		"foo=bar&bar=foo", "bar2=foo")
}

func TestBindingForm2(t *testing.T) {
	testFormBinding(t, http.MethodGet,
		"/?foo=bar&bar=foo", "/?bar2=foo",
		"", "")
}

func TestBindingFormEmbeddedStruct(t *testing.T) {
	testFormBindingEmbeddedStruct(t, http.MethodPost,
		"/", "/",
		"page=1&size=2&appkey=test-appkey", "bar2=foo")
}

func TestBindingFormEmbeddedStruct2(t *testing.T) {
	testFormBindingEmbeddedStruct(t, http.MethodGet,
		"/?page=1&size=2&appkey=test-appkey", "/?bar2=foo",
		"", "")
}

func TestBindingFormDefaultValue(t *testing.T) {
	testFormBindingDefaultValue(t, http.MethodPost,
		"/", "/",
		"foo=bar", "bar2=foo")
}

func TestBindingFormDefaultValue2(t *testing.T) {
	testFormBindingDefaultValue(t, http.MethodGet,
		"/?foo=bar", "/?bar2=foo",
		"", "")
}

func TestBindingFormForTime(t *testing.T) {
	testFormBindingForTime(t, http.MethodPost,
		"/", "/",
		"time_foo=2017-11-15&time_bar=&createTime=1562400033000000123&unixTime=1562400033&unixMilliTime=1562400033001&unixMicroTime=1562400033000012", "bar2=foo")
	testFormBindingForTimeNotUnixFormat(t, http.MethodPost,
		"/", "/",
		"time_foo=2017-11-15&createTime=bad&unixTime=bad&unixMilliTime=bad&unixMicroTime=bad", "bar2=foo")
	testFormBindingForTimeNotFormat(t, http.MethodPost,
		"/", "/",
		"time_foo=2017-11-15", "bar2=foo")
	testFormBindingForTimeFailFormat(t, http.MethodPost,
		"/", "/",
		"time_foo=2017-11-15", "bar2=foo")
	testFormBindingForTimeFailLocation(t, http.MethodPost,
		"/", "/",
		"time_foo=2017-11-15", "bar2=foo")
}

func TestBindingFormForTime2(t *testing.T) {
	testFormBindingForTime(t, http.MethodGet,
		"/?time_foo=2017-11-15&time_bar=&createTime=1562400033000000123&unixTime=1562400033&unixMilliTime=1562400033001&unixMicroTime=1562400033000012", "/?bar2=foo",
		"", "")
	testFormBindingForTimeNotUnixFormat(t, http.MethodPost,
		"/", "/",
		"time_foo=2017-11-15&createTime=bad&unixTime=bad&unixMilliTime=bad&unixMicroTime=bad", "bar2=foo")
	testFormBindingForTimeNotFormat(t, http.MethodGet,
		"/?time_foo=2017-11-15", "/?bar2=foo",
		"", "")
	testFormBindingForTimeFailFormat(t, http.MethodGet,
		"/?time_foo=2017-11-15", "/?bar2=foo",
		"", "")
	testFormBindingForTimeFailLocation(t, http.MethodGet,
		"/?time_foo=2017-11-15", "/?bar2=foo",
		"", "")
}

func TestFormBindingIgnoreField(t *testing.T) {
	testFormBindingIgnoreField(t, http.MethodPost,
		"/", "/",
		"-=bar", "")
}

func TestBindingFormInvalidName(t *testing.T) {
	testFormBindingInvalidName(t, http.MethodPost,
		"/", "/",
		"test_name=bar", "bar2=foo")
}

func TestBindingFormInvalidName2(t *testing.T) {
	testFormBindingInvalidName2(t, http.MethodPost,
		"/", "/",
		"map_foo=bar", "bar2=foo")
}

func TestBindingFormForType(t *testing.T) {
	testFormBindingForType(t, http.MethodPost,
		"/", "/",
		"map_foo={\"bar\":123}", "map_foo=1", "Map")

	testFormBindingForType(t, http.MethodPost,
		"/", "/",
		"slice_foo=1&slice_foo=2", "bar2=1&bar2=2", "Slice")

	testFormBindingForType(t, http.MethodGet,
		"/?slice_foo=1&slice_foo=2", "/?bar2=1&bar2=2",
		"", "", "Slice")

	testFormBindingForType(t, http.MethodPost,
		"/", "/",
		"slice_map_foo=1&slice_map_foo=2", "bar2=1&bar2=2", "SliceMap")

	testFormBindingForType(t, http.MethodGet,
		"/?slice_map_foo=1&slice_map_foo=2", "/?bar2=1&bar2=2",
		"", "", "SliceMap")

	testFormBindingForType(t, http.MethodPost,
		"/", "/",
		"ptr_bar=test", "bar2=test", "Ptr")

	testFormBindingForType(t, http.MethodGet,
		"/?ptr_bar=test", "/?bar2=test",
		"", "", "Ptr")

	testFormBindingForType(t, http.MethodPost,
		"/", "/",
		"idx=123", "id1=1", "Struct")

	testFormBindingForType(t, http.MethodGet,
		"/?idx=123", "/?id1=1",
		"", "", "Struct")

	testFormBindingForType(t, http.MethodPost,
		"/", "/",
		"name=thinkerou", "name1=ou", "StructPointer")

	testFormBindingForType(t, http.MethodGet,
		"/?name=thinkerou", "/?name1=ou",
		"", "", "StructPointer")
}

func TestBindingFormStringMap(t *testing.T) {
	testBodyBindingStringMap(t, Form,
		"/", "",
		`foo=bar&hello=world`, "")
	// Should pick the last value
	testBodyBindingStringMap(t, Form,
		"/", "",
		`foo=something&foo=bar&hello=world`, "")
}

func TestBindingFormStringSliceMap(t *testing.T) {
	obj := make(map[string][]string)
	req := requestWithBody(http.MethodPost, "/", "foo=something&foo=bar&hello=world")
	req.Header.Add("Content-Type", MIMEPOSTForm)
	err := Form.Bind(req, &obj)
	require.NoError(t, err)
	assert.NotNil(t, obj)
	assert.Len(t, obj, 2)
	target := map[string][]string{
		"foo":   {"something", "bar"},
		"hello": {"world"},
	}
	assert.True(t, reflect.DeepEqual(obj, target))

	objInvalid := make(map[string][]int)
	req = requestWithBody(http.MethodPost, "/", "foo=something&foo=bar&hello=world")
	req.Header.Add("Content-Type", MIMEPOSTForm)
	err = Form.Bind(req, &objInvalid)
	require.Error(t, err)
}

func TestBindingQuery(t *testing.T) {
	testQueryBinding(t, http.MethodPost,
		"/?foo=bar&bar=foo", "/",
		"foo=unused", "bar2=foo")
}

func TestBindingQuery2(t *testing.T) {
	testQueryBinding(t, http.MethodGet,
		"/?foo=bar&bar=foo", "/?bar2=foo",
		"foo=unused", "")
}

func TestBindingQueryFail(t *testing.T) {
	testQueryBindingFail(t, http.MethodPost,
		"/?map_foo=", "/",
		"map_foo=unused", "bar2=foo")
}

func TestBindingQueryFail2(t *testing.T) {
	testQueryBindingFail(t, http.MethodGet,
		"/?map_foo=", "/?bar2=foo",
		"map_foo=unused", "")
}

func TestBindingQueryBoolFail(t *testing.T) {
	testQueryBindingBoolFail(t, http.MethodGet,
		"/?bool_foo=fasl", "/?bar2=foo",
		"bool_foo=unused", "")
}

func TestBindingQueryStringMap(t *testing.T) {
	b := Query

	obj := make(map[string]string)
	req := requestWithBody(http.MethodGet, "/?foo=bar&hello=world", "")
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.NotNil(t, obj)
	assert.Len(t, obj, 2)
	assert.Equal(t, "bar", obj["foo"])
	assert.Equal(t, "world", obj["hello"])

	obj = make(map[string]string)
	req = requestWithBody(http.MethodGet, "/?foo=bar&foo=2&hello=world", "") // should pick last
	err = b.Bind(req, &obj)
	require.NoError(t, err)
	assert.NotNil(t, obj)
	assert.Len(t, obj, 2)
	assert.Equal(t, "2", obj["foo"])
	assert.Equal(t, "world", obj["hello"])
}

func TestBindingXML(t *testing.T) {
	testBodyBinding(t,
		XML, "xml",
		"/", "/",
		"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
}

func TestBindingXMLFail(t *testing.T) {
	testBodyBindingFail(t,
		XML, "xml",
		"/", "/",
		"<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) {
	testBodyBinding(t,
		YAML, "yaml",
		"/", "/",
		`foo: bar`, `bar: foo`)
}

func TestBindingYAMLStringMap(t *testing.T) {
	// YAML is a superset of JSON, so the test below is JSON (to avoid newlines)
	testBodyBindingStringMap(t, YAML,
		"/", "/",
		`{"foo": "bar", "hello": "world"}`, `{"nested": {"foo": "bar"}}`)
}

func TestBindingYAMLFail(t *testing.T) {
	testBodyBindingFail(t,
		YAML, "yaml",
		"/", "/",
		`foo:\nbar`, `bar: foo`)
}

func createFormPostRequest(t *testing.T) *http.Request {
	req, err := http.NewRequest(http.MethodPost, "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEPOSTForm)
	return req
}

func createDefaultFormPostRequest(t *testing.T) *http.Request {
	req, err := http.NewRequest(http.MethodPost, "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar"))
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEPOSTForm)
	return req
}

func createFormPostRequestForMap(t *testing.T) *http.Request {
	req, err := http.NewRequest(http.MethodPost, "/?map_foo=getfoo", bytes.NewBufferString("map_foo={\"bar\":123}"))
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEPOSTForm)
	return req
}

func createFormPostRequestForMapFail(t *testing.T) *http.Request {
	req, err := http.NewRequest(http.MethodPost, "/?map_foo=getfoo", bytes.NewBufferString("map_foo=hello"))
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEPOSTForm)
	return req
}

func createFormFilesMultipartRequest(t *testing.T) *http.Request {
	boundary := "--testboundary"
	body := new(bytes.Buffer)
	mw := multipart.NewWriter(body)
	defer mw.Close()

	require.NoError(t, mw.SetBoundary(boundary))
	require.NoError(t, mw.WriteField("foo", "bar"))
	require.NoError(t, mw.WriteField("bar", "foo"))

	f, err := os.Open("form.go")
	require.NoError(t, err)
	defer f.Close()
	fw, err1 := mw.CreateFormFile("file", "form.go")
	require.NoError(t, err1)
	_, err = io.Copy(fw, f)
	require.NoError(t, err)

	req, err2 := http.NewRequest(http.MethodPost, "/?foo=getfoo&bar=getbar", body)
	require.NoError(t, err2)
	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)

	return req
}

func createFormFilesMultipartRequestFail(t *testing.T) *http.Request {
	boundary := "--testboundary"
	body := new(bytes.Buffer)
	mw := multipart.NewWriter(body)
	defer mw.Close()

	require.NoError(t, mw.SetBoundary(boundary))
	require.NoError(t, mw.WriteField("foo", "bar"))
	require.NoError(t, mw.WriteField("bar", "foo"))

	f, err := os.Open("form.go")
	require.NoError(t, err)
	defer f.Close()
	fw, err1 := mw.CreateFormFile("file_foo", "form_foo.go")
	require.NoError(t, err1)
	_, err = io.Copy(fw, f)
	require.NoError(t, err)

	req, err2 := http.NewRequest(http.MethodPost, "/?foo=getfoo&bar=getbar", body)
	require.NoError(t, err2)
	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)

	return req
}

func createFormMultipartRequest(t *testing.T) *http.Request {
	boundary := "--testboundary"
	body := new(bytes.Buffer)
	mw := multipart.NewWriter(body)
	defer mw.Close()

	require.NoError(t, mw.SetBoundary(boundary))
	require.NoError(t, mw.WriteField("foo", "bar"))
	require.NoError(t, mw.WriteField("bar", "foo"))
	req, err := http.NewRequest(http.MethodPost, "/?foo=getfoo&bar=getbar", body)
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
	return req
}

func createFormMultipartRequestForMap(t *testing.T) *http.Request {
	boundary := "--testboundary"
	body := new(bytes.Buffer)
	mw := multipart.NewWriter(body)
	defer mw.Close()

	require.NoError(t, mw.SetBoundary(boundary))
	require.NoError(t, mw.WriteField("map_foo", "{\"bar\":123, \"name\":\"thinkerou\", \"pai\": 3.14}"))
	req, err := http.NewRequest(http.MethodPost, "/?map_foo=getfoo", body)
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
	return req
}

func createFormMultipartRequestForMapFail(t *testing.T) *http.Request {
	boundary := "--testboundary"
	body := new(bytes.Buffer)
	mw := multipart.NewWriter(body)
	defer mw.Close()

	require.NoError(t, mw.SetBoundary(boundary))
	require.NoError(t, mw.WriteField("map_foo", "3.14"))
	req, err := http.NewRequest(http.MethodPost, "/?map_foo=getfoo", body)
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
	return req
}

func TestBindingFormPost(t *testing.T) {
	req := createFormPostRequest(t)
	var obj FooBarStruct
	require.NoError(t, FormPost.Bind(req, &obj))

	assert.Equal(t, "form-urlencoded", FormPost.Name())
	assert.Equal(t, "bar", obj.Foo)
	assert.Equal(t, "foo", obj.Bar)
}

func TestBindingDefaultValueFormPost(t *testing.T) {
	req := createDefaultFormPostRequest(t)
	var obj FooDefaultBarStruct
	require.NoError(t, FormPost.Bind(req, &obj))

	assert.Equal(t, "bar", obj.Foo)
	assert.Equal(t, "hello", obj.Bar)
}

func TestBindingFormPostForMap(t *testing.T) {
	req := createFormPostRequestForMap(t)
	var obj FooStructForMapType
	err := FormPost.Bind(req, &obj)
	require.NoError(t, err)
	assert.InDelta(t, float64(123), obj.MapFoo["bar"].(float64), 0.01)
}

func TestBindingFormPostForMapFail(t *testing.T) {
	req := createFormPostRequestForMapFail(t)
	var obj FooStructForMapType
	err := FormPost.Bind(req, &obj)
	require.Error(t, err)
}

func TestBindingFormFilesMultipart(t *testing.T) {
	req := createFormFilesMultipartRequest(t)
	var obj FooBarFileStruct
	err := FormMultipart.Bind(req, &obj)
	require.NoError(t, err)

	// file from os
	f, _ := os.Open("form.go")
	defer f.Close()
	fileActual, _ := io.ReadAll(f)

	// file from multipart
	mf, _ := obj.File.Open()
	defer mf.Close()
	fileExpect, _ := io.ReadAll(mf)

	assert.Equal(t, "multipart/form-data", FormMultipart.Name())
	assert.Equal(t, "bar", obj.Foo)
	assert.Equal(t, "foo", obj.Bar)
	assert.Equal(t, fileExpect, fileActual)
}

func TestBindingFormFilesMultipartFail(t *testing.T) {
	req := createFormFilesMultipartRequestFail(t)
	var obj FooBarFileFailStruct
	err := FormMultipart.Bind(req, &obj)
	require.Error(t, err)
}

func TestBindingFormMultipart(t *testing.T) {
	req := createFormMultipartRequest(t)
	var obj FooBarStruct
	require.NoError(t, FormMultipart.Bind(req, &obj))

	assert.Equal(t, "multipart/form-data", FormMultipart.Name())
	assert.Equal(t, "bar", obj.Foo)
	assert.Equal(t, "foo", obj.Bar)
}

func TestBindingFormMultipartForMap(t *testing.T) {
	req := createFormMultipartRequestForMap(t)
	var obj FooStructForMapType
	err := FormMultipart.Bind(req, &obj)
	require.NoError(t, err)
	assert.InDelta(t, float64(123), obj.MapFoo["bar"].(float64), 0.01)
	assert.Equal(t, "thinkerou", obj.MapFoo["name"].(string))
	assert.InDelta(t, float64(3.14), obj.MapFoo["pai"].(float64), 0.01)
}

func TestBindingFormMultipartForMapFail(t *testing.T) {
	req := createFormMultipartRequestForMapFail(t)
	var obj FooStructForMapType
	err := FormMultipart.Bind(req, &obj)
	require.Error(t, err)
}

func TestBindingProtoBuf(t *testing.T) {
	test := &protoexample.Test{
		Label: proto.String("yes"),
	}
	data, _ := proto.Marshal(test)

	testProtoBodyBinding(t,
		ProtoBuf, "protobuf",
		"/", "/",
		string(data), string(data[1:]))
}

func TestBindingProtoBufFail(t *testing.T) {
	test := &protoexample.Test{
		Label: proto.String("yes"),
	}
	data, _ := proto.Marshal(test)

	testProtoBodyBindingFail(t,
		ProtoBuf, "protobuf",
		"/", "/",
		string(data), string(data[1:]))
}

func TestBindingBSON(t *testing.T) {
	var obj FooStruct
	obj.Foo = "bar"
	data, _ := bson.Marshal(&obj)
	testBodyBinding(t,
		BSON, "bson",
		"/", "/",
		string(data),
		// note: for badbody, we remove first byte to make it invalid
		string(data[1:]))
}

func TestValidationFails(t *testing.T) {
	var obj FooStruct
	req := requestWithBody(http.MethodPost, "/", `{"bar": "foo"}`)
	err := JSON.Bind(req, &obj)
	require.Error(t, err)
}

func TestValidationDisabled(t *testing.T) {
	backup := Validator
	Validator = nil
	defer func() { Validator = backup }()

	var obj FooStruct
	req := requestWithBody(http.MethodPost, "/", `{"bar": "foo"}`)
	err := JSON.Bind(req, &obj)
	require.NoError(t, err)
}

func TestRequiredSucceeds(t *testing.T) {
	type HogeStruct struct {
		Hoge *int `json:"hoge" binding:"required"`
	}

	var obj HogeStruct
	req := requestWithBody(http.MethodPost, "/", `{"hoge": 0}`)
	err := JSON.Bind(req, &obj)
	require.NoError(t, err)
}

func TestRequiredFails(t *testing.T) {
	type HogeStruct struct {
		Hoge *int `json:"foo" binding:"required"`
	}

	var obj HogeStruct
	req := requestWithBody(http.MethodPost, "/", `{"boen": 0}`)
	err := JSON.Bind(req, &obj)
	require.Error(t, err)
}

func TestHeaderBinding(t *testing.T) {
	h := Header
	assert.Equal(t, "header", h.Name())

	type tHeader struct {
		Limit int `header:"limit"`
	}

	var theader tHeader
	req := requestWithBody(http.MethodGet, "/", "")
	req.Header.Add("limit", "1000")
	require.NoError(t, h.Bind(req, &theader))
	assert.Equal(t, 1000, theader.Limit)

	req = requestWithBody(http.MethodGet, "/", "")
	req.Header.Add("fail", `{fail:fail}`)

	type failStruct struct {
		Fail map[string]any `header:"fail"`
	}

	err := h.Bind(req, &failStruct{})
	require.Error(t, err)
}

func TestUriBinding(t *testing.T) {
	b := Uri
	assert.Equal(t, "uri", b.Name())

	type Tag struct {
		Name string `uri:"name"`
	}
	var tag Tag
	m := make(map[string][]string)
	m["name"] = []string{"thinkerou"}
	require.NoError(t, b.BindUri(m, &tag))
	assert.Equal(t, "thinkerou", tag.Name)

	type NotSupportStruct struct {
		Name map[string]any `uri:"name"`
	}
	var not NotSupportStruct
	require.Error(t, b.BindUri(m, &not))
	assert.Equal(t, map[string]any(nil), not.Name)
}

func TestUriInnerBinding(t *testing.T) {
	type Tag struct {
		Name string `uri:"name"`
		S    struct {
			Age int `uri:"age"`
		}
	}

	expectedName := "mike"
	expectedAge := 25

	m := map[string][]string{
		"name": {expectedName},
		"age":  {strconv.Itoa(expectedAge)},
	}

	var tag Tag
	require.NoError(t, Uri.BindUri(m, &tag))
	assert.Equal(t, expectedName, tag.Name)
	assert.Equal(t, expectedAge, tag.S.Age)
}

func testFormBindingEmbeddedStruct(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := QueryTest{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, 1, obj.Page)
	assert.Equal(t, 2, obj.Size)
	assert.Equal(t, "test-appkey", obj.Appkey)
}

func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooBarStruct{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, "bar", obj.Foo)
	assert.Equal(t, "foo", obj.Bar)

	obj = FooBarStruct{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingDefaultValue(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooDefaultBarStruct{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, "bar", obj.Foo)
	assert.Equal(t, "hello", obj.Bar)

	obj = FooDefaultBarStruct{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func TestFormBindingFail(t *testing.T) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooBarStruct{}
	req, _ := http.NewRequest(http.MethodPost, "/", nil)
	err := b.Bind(req, &obj)
	require.Error(t, err)
}

func TestFormBindingMultipartFail(t *testing.T) {
	obj := FooBarStruct{}
	req, err := http.NewRequest(http.MethodPost, "/", strings.NewReader("foo=bar"))
	require.NoError(t, err)
	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+";boundary=testboundary")
	_, err = req.MultipartReader()
	require.NoError(t, err)
	err = Form.Bind(req, &obj)
	require.Error(t, err)
}

func TestFormPostBindingFail(t *testing.T) {
	b := FormPost
	assert.Equal(t, "form-urlencoded", b.Name())

	obj := FooBarStruct{}
	req, _ := http.NewRequest(http.MethodPost, "/", nil)
	err := b.Bind(req, &obj)
	require.Error(t, err)
}

func TestFormMultipartBindingFail(t *testing.T) {
	b := FormMultipart
	assert.Equal(t, "multipart/form-data", b.Name())

	obj := FooBarStruct{}
	req, _ := http.NewRequest(http.MethodPost, "/", nil)
	err := b.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooBarStructForTimeType{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)

	require.NoError(t, err)
	assert.Equal(t, int64(1510675200), obj.TimeFoo.Unix())
	assert.Equal(t, "Asia/Chongqing", obj.TimeFoo.Location().String())
	assert.Equal(t, int64(-62135596800), obj.TimeBar.Unix())
	assert.Equal(t, "UTC", obj.TimeBar.Location().String())
	assert.Equal(t, int64(1562400033000000123), obj.CreateTime.UnixNano())
	assert.Equal(t, int64(1562400033), obj.UnixTime.Unix())
	assert.Equal(t, int64(1562400033001), obj.UnixMilliTime.UnixMilli())
	assert.Equal(t, int64(1562400033000012), obj.UnixMicroTime.UnixMicro())

	obj = FooBarStructForTimeType{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingForTimeNotUnixFormat(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooStructForTimeTypeNotUnixFormat{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.Error(t, err)

	obj = FooStructForTimeTypeNotUnixFormat{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooStructForTimeTypeNotFormat{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.Error(t, err)

	obj = FooStructForTimeTypeNotFormat{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingForTimeFailFormat(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooStructForTimeTypeFailFormat{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.Error(t, err)

	obj = FooStructForTimeTypeFailFormat{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooStructForTimeTypeFailLocation{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.Error(t, err)

	obj = FooStructForTimeTypeFailLocation{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := FooStructForIgnoreFormTag{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.NoError(t, err)

	assert.Nil(t, obj.Foo)
}

func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := InvalidNameType{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Empty(t, obj.TestName)

	obj = InvalidNameType{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingInvalidName2(t *testing.T, method, path, badPath, body, badBody string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	obj := InvalidNameMapType{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.Error(t, err)

	obj = InvalidNameMapType{}
	req = requestWithBody(method, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody string, typ string) {
	b := Form
	assert.Equal(t, "form", b.Name())

	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	switch typ {
	case "Slice":
		obj := FooStructForSliceType{}
		err := b.Bind(req, &obj)
		require.NoError(t, err)
		assert.Equal(t, []int{1, 2}, obj.SliceFoo)

		obj = FooStructForSliceType{}
		req = requestWithBody(method, badPath, badBody)
		err = JSON.Bind(req, &obj)
		require.Error(t, err)
	case "Struct":
		obj := FooStructForStructType{}
		err := b.Bind(req, &obj)
		require.NoError(t, err)
		assert.Equal(t,
			struct {
				Idx int "form:\"idx\""
			}{Idx: 123},
			obj.StructFoo)
	case "StructPointer":
		obj := FooStructForStructPointerType{}
		err := b.Bind(req, &obj)
		require.NoError(t, err)
		assert.Equal(t,
			struct {
				Name string "form:\"name\""
			}{Name: "thinkerou"},
			*obj.StructPointerFoo)
	case "Map":
		obj := FooStructForMapType{}
		err := b.Bind(req, &obj)
		require.NoError(t, err)
		assert.InDelta(t, float64(123), obj.MapFoo["bar"].(float64), 0.01)
	case "SliceMap":
		obj := FooStructForSliceMapType{}
		err := b.Bind(req, &obj)
		require.Error(t, err)
	case "Ptr":
		obj := FooStructForStringPtrType{}
		err := b.Bind(req, &obj)
		require.NoError(t, err)
		assert.Nil(t, obj.PtrFoo)
		assert.Equal(t, "test", *obj.PtrBar)

		obj = FooStructForStringPtrType{}
		obj.PtrBar = new(string)
		err = b.Bind(req, &obj)
		require.NoError(t, err)
		assert.Equal(t, "test", *obj.PtrBar)

		objErr := FooStructForMapPtrType{}
		err = b.Bind(req, &objErr)
		require.Error(t, err)

		obj = FooStructForStringPtrType{}
		req = requestWithBody(method, badPath, badBody)
		err = b.Bind(req, &obj)
		require.Error(t, err)
	}
}

func testQueryBinding(t *testing.T, method, path, badPath, body, badBody string) {
	b := Query
	assert.Equal(t, "query", b.Name())

	obj := FooBarStruct{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, "bar", obj.Foo)
	assert.Equal(t, "foo", obj.Bar)
}

func testQueryBindingFail(t *testing.T, method, path, badPath, body, badBody string) {
	b := Query
	assert.Equal(t, "query", b.Name())

	obj := FooStructForMapType{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.Error(t, err)
}

func testQueryBindingBoolFail(t *testing.T, method, path, badPath, body, badBody string) {
	b := Query
	assert.Equal(t, "query", b.Name())

	obj := FooStructForBoolType{}
	req := requestWithBody(method, path, body)
	if method == http.MethodPost {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.Error(t, err)
}

func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	obj := FooStruct{}
	req := requestWithBody(http.MethodPost, path, body)
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, "bar", obj.Foo)

	obj = FooStruct{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testBodyBindingSlice(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	var obj1 []FooStruct
	req := requestWithBody(http.MethodPost, path, body)
	err := b.Bind(req, &obj1)
	require.NoError(t, err)

	var obj2 []FooStruct
	req = requestWithBody(http.MethodPost, badPath, badBody)
	err = JSON.Bind(req, &obj2)
	require.Error(t, err)
}

func testBodyBindingStringMap(t *testing.T, b Binding, path, badPath, body, badBody string) {
	obj := make(map[string]string)
	req := requestWithBody(http.MethodPost, path, body)
	if b.Name() == "form" {
		req.Header.Add("Content-Type", MIMEPOSTForm)
	}
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.NotNil(t, obj)
	assert.Len(t, obj, 2)
	assert.Equal(t, "bar", obj["foo"])
	assert.Equal(t, "world", obj["hello"])

	if badPath != "" && badBody != "" {
		obj = make(map[string]string)
		req = requestWithBody(http.MethodPost, badPath, badBody)
		err = b.Bind(req, &obj)
		require.Error(t, err)
	}

	objInt := make(map[string]int)
	req = requestWithBody(http.MethodPost, path, body)
	err = b.Bind(req, &objInt)
	require.Error(t, err)
}

func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	obj := FooStructUseNumber{}
	req := requestWithBody(http.MethodPost, path, body)
	EnableDecoderUseNumber = true
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	// we hope it is int64(123)
	v, e := obj.Foo.(json.Number).Int64()
	require.NoError(t, e)
	assert.Equal(t, int64(123), v)

	obj = FooStructUseNumber{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	obj := FooStructUseNumber{}
	req := requestWithBody(http.MethodPost, path, body)
	EnableDecoderUseNumber = false
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	// it will return float64(123) if not use EnableDecoderUseNumber
	// maybe it is not hoped
	assert.InDelta(t, float64(123), obj.Foo, 0.01)

	obj = FooStructUseNumber{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testBodyBindingDisallowUnknownFields(t *testing.T, b Binding, path, badPath, body, badBody string) {
	EnableDecoderDisallowUnknownFields = true
	defer func() {
		EnableDecoderDisallowUnknownFields = false
	}()

	obj := FooStructDisallowUnknownFields{}
	req := requestWithBody(http.MethodPost, path, body)
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, "bar", obj.Foo)

	obj = FooStructDisallowUnknownFields{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
	assert.Contains(t, err.Error(), "what")
}

func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	obj := FooStruct{}
	req := requestWithBody(http.MethodPost, path, body)
	err := b.Bind(req, &obj)
	require.Error(t, err)
	assert.Empty(t, obj.Foo)

	obj = FooStruct{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	err = JSON.Bind(req, &obj)
	require.Error(t, err)
}

func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	obj := protoexample.Test{}
	req := requestWithBody(http.MethodPost, path, body)
	req.Header.Add("Content-Type", MIMEPROTOBUF)
	err := b.Bind(req, &obj)
	require.NoError(t, err)
	assert.Equal(t, "yes", *obj.Label)

	obj = protoexample.Test{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	req.Header.Add("Content-Type", MIMEPROTOBUF)
	err = ProtoBuf.Bind(req, &obj)
	require.Error(t, err)
}

type hook struct{}

func (h hook) Read([]byte) (int, error) {
	return 0, errors.New("error")
}

type failRead struct{}

func (f *failRead) Read(b []byte) (n int, err error) {
	return 0, errors.New("my fail")
}

func (f *failRead) Close() error {
	return nil
}

func TestPlainBinding(t *testing.T) {
	p := Plain
	assert.Equal(t, "plain", p.Name())

	var s string
	req := requestWithBody(http.MethodPost, "/", "test string")
	require.NoError(t, p.Bind(req, &s))
	assert.Equal(t, "test string", s)

	var bs []byte
	req = requestWithBody(http.MethodPost, "/", "test []byte")
	require.NoError(t, p.Bind(req, &bs))
	assert.Equal(t, bs, []byte("test []byte"))

	var i int
	req = requestWithBody(http.MethodPost, "/", "test fail")
	require.Error(t, p.Bind(req, &i))

	req = requestWithBody(http.MethodPost, "/", "")
	req.Body = &failRead{}
	require.Error(t, p.Bind(req, &s))

	req = requestWithBody(http.MethodPost, "/", "")
	require.NoError(t, p.Bind(req, nil))

	var ptr *string
	req = requestWithBody(http.MethodPost, "/", "")
	require.NoError(t, p.Bind(req, ptr))
}

func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
	assert.Equal(t, name, b.Name())

	obj := protoexample.Test{}
	req := requestWithBody(http.MethodPost, path, body)

	req.Body = io.NopCloser(&hook{})
	req.Header.Add("Content-Type", MIMEPROTOBUF)
	err := b.Bind(req, &obj)
	require.Error(t, err)

	invalidobj := FooStruct{}
	req.Body = io.NopCloser(strings.NewReader(`{"msg":"hello"}`))
	req.Header.Add("Content-Type", MIMEPROTOBUF)
	err = b.Bind(req, &invalidobj)
	require.Error(t, err)
	assert.Equal(t, "obj is not ProtoMessage", err.Error())

	obj = protoexample.Test{}
	req = requestWithBody(http.MethodPost, badPath, badBody)
	req.Header.Add("Content-Type", MIMEPROTOBUF)
	err = ProtoBuf.Bind(req, &obj)
	require.Error(t, err)
}

func requestWithBody(method, path, body string) (req *http.Request) {
	req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
	return
}


================================================
FILE: binding/bson.go
================================================
// Copyright 2025 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 (
	"io"
	"net/http"

	"go.mongodb.org/mongo-driver/v2/bson"
)

type bsonBinding struct{}

func (bsonBinding) Name() string {
	return "bson"
}

func (b bsonBinding) Bind(req *http.Request, obj any) error {
	buf, err := io.ReadAll(req.Body)
	if err == nil {
		err = b.BindBody(buf, obj)
	}
	return err
}

func (bsonBinding) BindBody(body []byte, obj any) error {
	return bson.Unmarshal(body, obj)
}


================================================
FILE: binding/default_validator.go
================================================
// Copyright 2017 Manu Martinez-Almeida. 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 (
	"reflect"
	"strconv"
	"strings"
	"sync"

	"github.com/go-playground/validator/v10"
)

type defaultValidator struct {
	once     sync.Once
	validate *validator.Validate
}

type SliceValidationError []error

// Error concatenates all error elements in SliceValidationError into a single string separated by \n.
func (err SliceValidationError) Error() string {
	if len(err) == 0 {
		return ""
	}

	var b strings.Builder
	for i := range len(err) {
		if err[i] != nil {
			if b.Len() > 0 {
				b.WriteString("\n")
			}
			b.WriteString("[" + strconv.Itoa(i) + "]: " + err[i].Error())
		}
	}
	return b.String()
}

var _ StructValidator = (*defaultValidator)(nil)

// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type.
func (v *defaultValidator) ValidateStruct(obj any) error {
	if obj == nil {
		return nil
	}

	value := reflect.ValueOf(obj)
	switch value.Kind() {
	case reflect.Ptr:
		if value.Elem().Kind() != reflect.Struct {
			return v.ValidateStruct(value.Elem().Interface())
		}
		return v.validateStruct(obj)
	case reflect.Struct:
		return v.validateStruct(obj)
	case reflect.Slice, reflect.Array:
		count := value.Len()
		validateRet := make(SliceValidationError, 0)
		for i := range count {
			if err := v.ValidateStruct(value.Index(i).Interface()); err != nil {
				validateRet = append(validateRet, err)
			}
		}
		if len(validateRet) == 0 {
			return nil
		}
		return validateRet
	default:
		return nil
	}
}

// validateStruct receives struct type
func (v *defaultValidator) validateStruct(obj any) error {
	v.lazyinit()
	return v.validate.Struct(obj)
}

// Engine returns the underlying validator engine which powers the default
// Validator instance. This is useful if you want to register custom validations
// or struct level validations. See validator GoDoc for more info -
// https://pkg.go.dev/github.com/go-playground/validator/v10
func (v *defaultValidator) Engine() any {
	v.lazyinit()
	return v.validate
}

func (v *defaultValidator) lazyinit() {
	v.once.Do(func() {
		v.validate = validator.New()
		v.validate.SetTagName("binding")
	})
}


================================================
FILE: binding/default_validator_benchmark_test.go
================================================
// 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 (
	"errors"
	"strconv"
	"testing"
)

func BenchmarkSliceValidationError(b *testing.B) {
	const size int = 100
	e := make(SliceValidationError, size)
	for j := 0; j < size; j++ {
		e[j] = errors.New(strconv.Itoa(j))
	}

	b.ReportAllocs()

	for b.Loop() {
		if len(e.Error()) == 0 {
			b.Errorf("error")
		}
	}
}


================================================
FILE: binding/default_validator_test.go
================================================
// Copyright 2020 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 (
	"errors"
	"testing"
)

func TestSliceValidationError(t *testing.T) {
	tests := []struct {
		name string
		err  SliceValidationError
		want string
	}{
		{"has nil elements", SliceValidationError{errors.New("test error"), nil}, "[0]: test error"},
		{"has zero elements", SliceValidationError{}, ""},
		{"has one element", SliceValidationError{errors.New("test one error")}, "[0]: test one error"},
		{
			"has two elements",
			SliceValidationError{
				errors.New("first error"),
				errors.New("second error"),
			},
			"[0]: first error\n[1]: second error",
		},
		{
			"has many elements",
			SliceValidationError{
				errors.New("first error"),
				errors.New("second error"),
				nil,
				nil,
				nil,
				errors.New("last error"),
			},
			"[0]: first error\n[1]: second error\n[5]: last error",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := tt.err.Error(); got != tt.want {
				t.Errorf("SliceValidationError.Error() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestDefaultValidator(t *testing.T) {
	type exampleStruct struct {
		A string `binding:"max=8"`
		B int    `binding:"gt=0"`
	}
	tests := []struct {
		name    string
		v       *defaultValidator
		obj     any
		wantErr bool
	}{
		{"validate nil obj", &defaultValidator{}, nil, false},
		{"validate int obj", &defaultValidator{}, 3, false},
		{"validate struct failed-1", &defaultValidator{}, exampleStruct{A: "123456789", B: 1}, true},
		{"validate struct failed-2", &defaultValidator{}, exampleStruct{A: "12345678", B: 0}, true},
		{"validate struct passed", &defaultValidator{}, exampleStruct{A: "12345678", B: 1}, false},
		{"validate *struct failed-1", &defaultValidator{}, &exampleStruct{A: "123456789", B: 1}, true},
		{"validate *struct failed-2", &defaultValidator{}, &exampleStruct{A: "12345678", B: 0}, true},
		{"validate *struct passed", &defaultValidator{}, &exampleStruct{A: "12345678", B: 1}, false},
		{"validate []struct failed-1", &defaultValidator{}, []exampleStruct{{A: "123456789", B: 1}}, true},
		{"validate []struct failed-2", &defaultValidator{}, []exampleStruct{{A: "12345678", B: 0}}, true},
		{"validate []struct passed", &defaultValidator{}, []exampleStruct{{A: "12345678", B: 1}}, false},
		{"validate []*struct failed-1", &defaultValidator{}, []*exampleStruct{{A: "123456789", B: 1}}, true},
		{"validate []*struct failed-2", &defaultValidator{}, []*exampleStruct{{A: "12345678", B: 0}}, true},
		{"validate []*struct passed", &defaultValidator{}, []*exampleStruct{{A: "12345678", B: 1}}, false},
		{"validate *[]struct failed-1", &defaultValidator{}, &[]exampleStruct{{A: "123456789", B: 1}}, true},
		{"validate *[]struct failed-2", &defaultValidator{}, &[]exampleStruct{{A: "12345678", B: 0}}, true},
		{"validate *[]struct passed", &defaultValidator{}, &[]exampleStruct{{A: "12345678", B: 1}}, false},
		{"validate *[]*struct failed-1", &defaultValidator{}, &[]*exampleStruct{{A: "123456789", B: 1}}, true},
		{"validate *[]*struct failed-2", &defaultValidator{}, &[]*exampleStruct{{A: "12345678", B: 0}}, true},
		{"validate *[]*struct passed", &defaultValidator{}, &[]*exampleStruct{{A: "12345678", B: 1}}, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.v.ValidateStruct(tt.obj); (err != nil) != tt.wantErr {
				t.Errorf("defaultValidator.Validate() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}


================================================
FILE: binding/form.go
================================================
// Copyright 2014 Manu Martinez-Almeida. 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 (
	"errors"
	"net/http"
)

const defaultMemory = 32 << 20

type (
	formBinding          struct{}
	formPostBinding      struct{}
	formMultipartBinding struct{}
)

func (formBinding) Name() string {
	return "form"
}

func (formBinding) Bind(req *http.Request, obj any) error {
	if err := req.ParseForm(); err != nil {
		return err
	}
	if err := req.ParseMultipartForm(defaultMemory); err != nil && !errors.Is(err, http.ErrNotMultipart) {
		return err
	}
	if err := mapForm(obj, req.Form); err != nil {
		return err
	}
	return validate(obj)
}

func (formPostBinding) Name() string {
	return "form-urlencoded"
}

func (formPostBinding) Bind(req *http.Request, obj any) error {
	if err := req.ParseForm(); err != nil {
		return err
	}
	if err := mapForm(obj, req.PostForm); err != nil {
		return err
	}
	return validate(obj)
}

func (formMultipartBinding) Name() string {
	return "multipart/form-data"
}

func (formMultipartBinding) Bind(req *http.Request, obj any) error {
	if err := req.ParseMultipartForm(defaultMemory); err != nil {
		return err
	}
	if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil {
		return err
	}

	return validate(obj)
}


================================================
FILE: binding/form_mapping.go
================================================
// Copyright 2014 Manu Martinez-Almeida. 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 (
	"encoding"
	"errors"
	"fmt"
	"maps"
	"mime/multipart"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin/codec/json"
	"github.com/gin-gonic/gin/internal/bytesconv"
)

var (
	errUnknownType = errors.New("unknown type")

	// ErrConvertMapStringSlice can not convert to map[string][]string
	ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings")

	// ErrConvertToMapString can not convert to map[string]string
	ErrConvertToMapString = errors.New("can not convert to map of strings")
)

func mapURI(ptr any, m map[string][]string) error {
	return mapFormByTag(ptr, m, "uri")
}

func mapForm(ptr any, form map[string][]string) error {
	return mapFormByTag(ptr, form, "form")
}

func MapFormWithTag(ptr any, form map[string][]string, tag string) error {
	return mapFormByTag(ptr, form, tag)
}

var emptyField = reflect.StructField{}

func mapFormByTag(ptr any, form map[string][]string, tag string) error {
	// Check if ptr is a map
	ptrVal := reflect.ValueOf(ptr)
	var pointed any
	if ptrVal.Kind() == reflect.Ptr {
		ptrVal = ptrVal.Elem()
		pointed = ptrVal.Interface()
	}
	if ptrVal.Kind() == reflect.Map &&
		ptrVal.Type().Key().Kind() == reflect.String {
		if pointed != nil {
			ptr = pointed
		}
		return setFormMap(ptr, form)
	}

	return mappingByPtr(ptr, formSource(form), tag)
}

// setter tries to set value on a walking by fields of a struct
type setter interface {
	TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSet bool, err error)
}

type formSource map[string][]string

var _ setter = formSource(nil)

// TrySet tries to set a value by request's form source (like map[string][]string)
func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSet bool, err error) {
	return setByForm(value, field, form, tagValue, opt)
}

func mappingByPtr(ptr any, setter setter, tag string) error {
	_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
	return err
}

func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
	if field.Tag.Get(tag) == "-" { // just ignoring this field
		return false, nil
	}

	vKind := value.Kind()

	if vKind == reflect.Ptr {
		var isNew bool
		vPtr := value
		if value.IsNil() {
			isNew = true
			vPtr = reflect.New(value.Type().Elem())
		}
		isSet, err := mapping(vPtr.Elem(), field, setter, tag)
		if err != nil {
			return false, err
		}
		if isNew && isSet {
			value.Set(vPtr)
		}
		return isSet, nil
	}

	if vKind != reflect.Struct || !field.Anonymous {
		ok, err := tryToSetValue(value, field, setter, tag)
		if err != nil {
			return false, err
		}
		if ok {
			return true, nil
		}
	}

	if vKind == reflect.Struct {
		tValue := value.Type()

		var isSet bool
		for i := range value.NumField() {
			sf := tValue.Field(i)
			if sf.PkgPath != "" && !sf.Anonymous { // unexported
				continue
			}
			ok, err := mapping(value.Field(i), sf, setter, tag)
			if err != nil {
				return false, err
			}
			isSet = isSet || ok
		}
		return isSet, nil
	}
	return false, nil
}

type setOptions struct {
	isDefaultExists bool
	defaultValue    string
	// parser specifies what interface to use for reading the request & default values (e.g. `encoding.TextUnmarshaler`)
	parser string
}

func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
	var tagValue string
	var setOpt setOptions

	tagValue = field.Tag.Get(tag)
	tagValue, opts := head(tagValue, ",")

	if tagValue == "" { // default value is FieldName
		tagValue = field.Name
	}
	if tagValue == "" { // when field is "emptyField" variable
		return false, nil
	}

	var opt string
	for len(opts) > 0 {
		opt, opts = head(opts, ",")

		if k, v := head(opt, "="); k == "default" {
			setOpt.isDefaultExists = true
			setOpt.defaultValue = v

			// convert semicolon-separated default values to csv-separated values for processing in setByForm
			if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Array {
				cfTag := field.Tag.Get("collection_format")
				if cfTag == "" || cfTag == "multi" || cfTag == "csv" {
					setOpt.defaultValue = strings.ReplaceAll(v, ";", ",")
				}
			}
		} else if k, v = head(opt, "="); k == "parser" {
			setOpt.parser = v
		}
	}

	return setter.TrySet(value, field, tagValue, setOpt)
}

// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
type BindUnmarshaler interface {
	// UnmarshalParam decodes and assigns a value from a form or query param.
	UnmarshalParam(param string) error
}

// trySetCustom tries to set a custom type value
// If the value implements the BindUnmarshaler interface, it will be used to set the value, we will return `true`
// to skip the default value setting.
func trySetCustom(val string, value reflect.Value) (isSet bool, err error) {
	switch v := value.Addr().Interface().(type) {
	case BindUnmarshaler:
		return true, v.UnmarshalParam(val)
	}
	return false, nil
}

// trySetUsingParser tries to set a custom type value based on the presence of the "parser" tag on the field.
// If the parser tag does not exist or does not match any of the supported parsers, gin will skip over this.
func trySetUsingParser(val string, value reflect.Value, parser string) (isSet bool, err error) {
	switch parser {
	case "encoding.TextUnmarshaler":
		v, ok := value.Addr().Interface().(encoding.TextUnmarshaler)
		if !ok {
			return false, nil
		}
		return true, v.UnmarshalText([]byte(val))
	}
	return false, nil
}

func trySplit(vs []string, field reflect.StructField) (newVs []string, err error) {
	cfTag := field.Tag.Get("collection_format")
	if cfTag == "" || cfTag == "multi" {
		return vs, nil
	}

	var sep string
	switch cfTag {
	case "csv":
		sep = ","
	case "ssv":
		sep = " "
	case "tsv":
		sep = "\t"
	case "pipes":
		sep = "|"
	default:
		return vs, fmt.Errorf("%s is not supported in the collection_format. (multi, csv, ssv, tsv, pipes)", cfTag)
	}

	totalLength := 0
	for _, v := range vs {
		totalLength += strings.Count(v, sep) + 1
	}
	newVs = make([]string, 0, totalLength)
	for _, v := range vs {
		newVs = append(newVs, strings.Split(v, sep)...)
	}

	return newVs, nil
}

func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) {
	vs, ok := form[tagValue]
	if !ok && !opt.isDefaultExists {
		return false, nil
	}

	switch value.Kind() {
	case reflect.Slice:
		if len(vs) == 0 {
			if !opt.isDefaultExists {
				return false, nil
			}

			vs = []string{opt.defaultValue}
			// pre-process the default value for multi if present
			cfTag := field.Tag.Get("collection_format")
			if cfTag == "" || cfTag == "multi" {
				vs = strings.Split(opt.defaultValue, ",")
			}
		}

		if ok, err = trySetUsingParser(vs[0], value, opt.parser); ok {
			return ok, err
		} else if ok, err = trySetCustom(vs[0], value); ok {
			return ok, err
		}

		if vs, err = trySplit(vs, field); err != nil {
			return false, err
		}

		return true, setSlice(vs, value, field, opt)
	case reflect.Array:
		if len(vs) == 0 {
			if !opt.isDefaultExists {
				return false, nil
			}

			vs = []string{opt.defaultValue}
			// pre-process the default value for multi if present
			cfTag := field.Tag.Get("collection_format")
			if cfTag == "" || cfTag == "multi" {
				vs = strings.Split(opt.defaultValue, ",")
			}
		}

		if ok, err = trySetUsingParser(vs[0], value, opt.parser); ok {
			return ok, err
		} else if ok, err = trySetCustom(vs[0], value); ok {
			return ok, err
		}

		if vs, err = trySplit(vs, field); err != nil {
			return false, err
		}

		if len(vs) != value.Len() {
			return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
		}

		return true, setArray(vs, value, field, opt)
	default:
		var val string
		if !ok || len(vs) == 0 || (len(vs) > 0 && vs[0] == "") {
			val = opt.defaultValue
		} else if len(vs) > 0 {
			val = vs[0]
		}

		if ok, err = trySetUsingParser(val, value, opt.parser); ok {
			return ok, err
		} else if ok, err = trySetCustom(val, value); ok {
			return ok, err
		}
		return true, setWithProperType(val, value, field, opt)
	}
}

func setWithProperType(val string, value reflect.Value, field reflect.StructField, opt setOptions) error {
	// this if-check is required for parsing nested types like []MyId, where MyId is [12]byte
	if ok, err := trySetUsingParser(val, value, opt.parser); ok {
		return err
	} else if ok, err = trySetCustom(val, value); ok {
		return err
	}

	// If it is a string type, no spaces are removed, and the user data is not modified here
	if value.Kind() != reflect.String {
		val = strings.TrimSpace(val)
	}

	switch value.Kind() {
	case reflect.Int:
		return setIntField(val, 0, value)
	case reflect.Int8:
		return setIntField(val, 8, value)
	case reflect.Int16:
		return setIntField(val, 16, value)
	case reflect.Int32:
		return setIntField(val, 32, value)
	case reflect.Int64:
		switch value.Interface().(type) {
		case time.Duration:
			return setTimeDuration(val, value)
		}
		return setIntField(val, 64, value)
	case reflect.Uint:
		return setUintField(val, 0, value)
	case reflect.Uint8:
		return setUintField(val, 8, value)
	case reflect.Uint16:
		return setUintField(val, 16, value)
	case reflect.Uint32:
		return setUintField(val, 32, value)
	case reflect.Uint64:
		return setUintField(val, 64, value)
	case reflect.Bool:
		return setBoolField(val, value)
	case reflect.Float32:
		return setFloatField(val, 32, value)
	case reflect.Float64:
		return setFloatField(val, 64, value)
	case reflect.String:
		value.SetString(val)
	case reflect.Struct:
		switch value.Interface().(type) {
		case time.Time:
			return setTimeField(val, field, value)
		case multipart.FileHeader:
			return nil
		}
		return json.API.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
	case reflect.Map:
		return json.API.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
	case reflect.Ptr:
		if !value.Elem().IsValid() {
			value.Set(reflect.New(value.Type().Elem()))
		}
		return setWithProperType(val, value.Elem(), field, opt)
	default:
		return errUnknownType
	}
	return nil
}

func setIntField(val string, bitSize int, field reflect.Value) error {
	if val == "" {
		val = "0"
	}
	intVal, err := strconv.ParseInt(val, 10, bitSize)
	if err == nil {
		field.SetInt(intVal)
	}
	return err
}

func setUintField(val string, bitSize int, field reflect.Value) error {
	if val == "" {
		val = "0"
	}
	uintVal, err := strconv.ParseUint(val, 10, bitSize)
	if err == nil {
		field.SetUint(uintVal)
	}
	return err
}

func setBoolField(val string, field reflect.Value) error {
	if val == "" {
		val = "false"
	}
	boolVal, err := strconv.ParseBool(val)
	if err == nil {
		field.SetBool(boolVal)
	}
	return err
}

func setFloatField(val string, bitSize int, field reflect.Value) error {
	if val == "" {
		val = "0.0"
	}
	floatVal, err := strconv.ParseFloat(val, bitSize)
	if err == nil {
		field.SetFloat(floatVal)
	}
	return err
}

func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
	timeFormat := structField.Tag.Get("time_format")
	if timeFormat == "" {
		timeFormat = time.RFC3339
	}

	if val == "" {
		value.Set(reflect.ValueOf(time.Time{}))
		return nil
	}

	switch tf := strings.ToLower(timeFormat); tf {
	case "unix", "unixmilli", "unixmicro", "unixnano":
		tv, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return err
		}

		var t time.Time
		switch tf {
		case "unix":
			t = time.Unix(tv, 0)
		case "unixmilli":
			t = time.UnixMilli(tv)
		case "unixmicro":
			t = time.UnixMicro(tv)
		default:
			t = time.Unix(0, tv)
		}

		value.Set(reflect.ValueOf(t))
		return nil
	}

	l := time.Local
	if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
		l = time.UTC
	}

	if locTag := structField.Tag.Get("time_location"); locTag != "" {
		loc, err := time.LoadLocation(locTag)
		if err != nil {
			return err
		}
		l = loc
	}

	t, err := time.ParseInLocation(timeFormat, val, l)
	if err != nil {
		return err
	}

	value.Set(reflect.ValueOf(t))
	return nil
}

func setArray(vals []string, value reflect.Value, field reflect.StructField, opt setOptions) error {
	for i, s := range vals {
		err := setWithProperType(s, value.Index(i), field, opt)
		if err != nil {
			return err
		}
	}
	return nil
}

func setSlice(vals []string, value reflect.Value, field reflect.StructField, opt setOptions) error {
	slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
	err := setArray(vals, slice, field, opt)
	if err != nil {
		return err
	}
	value.Set(slice)
	return nil
}

func setTimeDuration(val string, value reflect.Value) error {
	if val == "" {
		val = "0"
	}

	d, err := time.ParseDuration(val)
	if err != nil {
		return err
	}
	value.Set(reflect.ValueOf(d))
	return nil
}

func head(str, sep string) (head string, tail string) {
	head, tail, _ = strings.Cut(str, sep)
	return head, tail
}

func setFormMap(ptr any, form map[string][]string) error {
	el := reflect.TypeOf(ptr).Elem()

	if el.Kind() == reflect.Slice {
		ptrMap, ok := ptr.(map[string][]string)
		if !ok {
			return ErrConvertMapStringSlice
		}
		maps.Copy(ptrMap, form)

		return nil
	}

	ptrMap, ok := ptr.(map[string]string)
	if !ok {
		return ErrConvertToMapString
	}
	for k, v := range form {
		ptrMap[k] = v[len(v)-1] // pick last
	}

	return nil
}


================================================
FILE: binding/form_mapping_benchmark_test.go
================================================
// Copyright 2019 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"
	"time"

	"github.com/stretchr/testify/assert"
)

var form = map[string][]string{
	"name":      {"mike"},
	"friends":   {"anna", "nicole"},
	"id_number": {"12345678"},
	"id_date":   {"2018-01-20"},
}

type structFull struct {
	Name    string   `form:"name"`
	Age     int      `form:"age,default=25"`
	Friends []string `form:"friends"`
	ID      *struct {
		Number      string    `form:"id_number"`
		DateOfIssue time.Time `form:"id_date" time_format:"2006-01-02" time_utc:"true"`
	}
	Nationality *string `form:"nationality"`
}

func BenchmarkMapFormFull(b *testing.B) {
	var s structFull
	for b.Loop() {
		err := mapForm(&s, form)
		if err != nil {
			b.Fatalf("Error on a form mapping")
		}
	}
	b.StopTimer()

	t := b
	assert.Equal(t, "mike", s.Name)
	assert.Equal(t, 25, s.Age)
	assert.Equal(t, []string{"anna", "nicole"}, s.Friends)
	assert.Equal(t, "12345678", s.ID.Number)
	assert.Equal(t, time.Date(2018, 1, 20, 0, 0, 0, 0, time.UTC), s.ID.DateOfIssue)
	assert.Nil(t, s.Nationality)
}

type structName struct {
	Name string `form:"name"`
}

func BenchmarkMapFormName(b *testing.B) {
	var s structName
	for b.Loop() {
		err := mapForm(&s, form)
		if err != nil {
			b.Fatalf("Error on a form mapping")
		}
	}
	b.StopTimer()

	t := b
	assert.Equal(t, "mike", s.Name)
}


================================================
FILE: binding/form_mapping_test.go
================================================
// Copyright 2019 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 (
	"encoding"
	"encoding/hex"
	"errors"
	"mime/multipart"
	"reflect"
	"strconv"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestMappingBaseTypes(t *testing.T) {
	intPtr := func(i int) *int {
		return &i
	}
	for _, tt := range []struct {
		name   string
		value  any
		form   string
		expect any
	}{
		{"base type", struct{ F int }{}, "9", int(9)},
		{"base type", struct{ F int8 }{}, "9", int8(9)},
		{"base type", struct{ F int16 }{}, "9", int16(9)},
		{"base type", struct{ F int32 }{}, "9", int32(9)},
		{"base type", struct{ F int64 }{}, "9", int64(9)},
		{"base type", struct{ F uint }{}, "9", uint(9)},
		{"base type", struct{ F uint8 }{}, "9", uint8(9)},
		{"base type", struct{ F uint16 }{}, "9", uint16(9)},
		{"base type", struct{ F uint32 }{}, "9", uint32(9)},
		{"base type", struct{ F uint64 }{}, "9", uint64(9)},
		{"base type", struct{ F bool }{}, "True", true},
		{"base type", struct{ F float32 }{}, "9.1", float32(9.1)},
		{"base type", struct{ F float64 }{}, "9.1", float64(9.1)},
		{"base type", struct{ F string }{}, "test", string("test")},
		{"base type", struct{ F *int }{}, "9", intPtr(9)},

		// zero values
		{"zero value", struct{ F int }{}, "", int(0)},
		{"zero value", struct{ F uint }{}, "", uint(0)},
		{"zero value", struct{ F bool }{}, "", false},
		{"zero value", struct{ F float32 }{}, "", float32(0)},
		{"file value", struct{ F *multipart.FileHeader }{}, "", &multipart.FileHeader{}},
	} {
		tp := reflect.TypeOf(tt.value)
		testName := tt.name + ":" + tp.Field(0).Type.String()

		val := reflect.New(reflect.TypeOf(tt.value))
		val.Elem().Set(reflect.ValueOf(tt.value))

		field := val.Elem().Type().Field(0)

		_, err := mapping(val, emptyField, formSource{field.Name: {tt.form}}, "form")
		require.NoError(t, err, testName)

		actual := val.Elem().Field(0).Interface()
		assert.Equal(t, tt.expect, actual, testName)
	}
}

func TestMappingDefault(t *testing.T) {
	var s struct {
		Str   string `form:",default=defaultVal"`
		Int   int    `form:",default=9"`
		Slice []int  `form:",default=9"`
		Array [1]int `form:",default=9"`
	}
	err := mappingByPtr(&s, formSource{}, "form")
	require.NoError(t, err)

	assert.Equal(t, "defaultVal", s.Str)
	assert.Equal(t, 9, s.Int)
	assert.Equal(t, []int{9}, s.Slice)
	assert.Equal(t, [1]int{9}, s.Array)
}

func TestMappingSkipField(t *testing.T) {
	var s struct {
		A int
	}
	err := mappingByPtr(&s, formSource{}, "form")
	require.NoError(t, err)

	assert.Equal(t, 0, s.A)
}

func TestMappingIgnoreField(t *testing.T) {
	var s struct {
		A int `form:"A"`
		B int `form:"-"`
	}
	err := mappingByPtr(&s, formSource{"A": {"9"}, "B": {"9"}}, "form")
	require.NoError(t, err)

	assert.Equal(t, 9, s.A)
	assert.Equal(t, 0, s.B)
}

func TestMappingUnexportedField(t *testing.T) {
	var s struct {
		A int `form:"a"`
		b int `form:"b"`
	}
	err := mappingByPtr(&s, formSource{"a": {"9"}, "b": {"9"}}, "form")
	require.NoError(t, err)

	assert.Equal(t, 9, s.A)
	assert.Equal(t, 0, s.b)
}

func TestMappingPrivateField(t *testing.T) {
	var s struct {
		f int `form:"field"`
	}
	err := mappingByPtr(&s, formSource{"field": {"6"}}, "form")
	require.NoError(t, err)
	assert.Equal(t, 0, s.f)
}

func TestMappingUnknownFieldType(t *testing.T) {
	var s struct {
		U uintptr
	}

	err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form")
	require.Error(t, err)
	assert.Equal(t, errUnknownType, err)
}

func TestMappingURI(t *testing.T) {
	var s struct {
		F int `uri:"field"`
	}
	err := mapURI(&s, map[string][]string{"field": {"6"}})
	require.NoError(t, err)
	assert.Equal(t, 6, s.F)
}

func TestMappingForm(t *testing.T) {
	var s struct {
		F int `form:"field"`
	}
	err := mapForm(&s, map[string][]string{"field": {"6"}})
	require.NoError(t, err)
	assert.Equal(t, 6, s.F)
}

func TestMappingFormFieldNotSent(t *testing.T) {
	var s struct {
		F string `form:"field,default=defVal"`
	}
	err := mapForm(&s, map[string][]string{})
	require.NoError(t, err)
	assert.Equal(t, "defVal", s.F)
}

func TestMappingFormWithEmptyToDefault(t *testing.T) {
	var s struct {
		F string `form:"field,default=DefVal"`
	}
	err := mapForm(&s, map[string][]string{"field": {""}})
	require.NoError(t, err)
	assert.Equal(t, "DefVal", s.F)
}

func TestMapFormWithTag(t *testing.T) {
	var s struct {
		F int `externalTag:"field"`
	}
	err := MapFormWithTag(&s, map[string][]string{"field": {"6"}}, "externalTag")
	require.NoError(t, err)
	assert.Equal(t, 6, s.F)
}

func TestMappingTime(t *testing.T) {
	var s struct {
		Time      time.Time
		LocalTime time.Time `time_format:"2006-01-02"`
		ZeroValue time.Time
		CSTTime   time.Time `time_format:"2006-01-02" time_location:"Asia/Shanghai"`
		UTCTime   time.Time `time_format:"2006-01-02" time_utc:"1"`
	}

	var err error
	time.Local, err = time.LoadLocation("Europe/Berlin")
	require.NoError(t, err)

	err = mapForm(&s, map[string][]string{
		"Time":      {"2019-01-20T16:02:58Z"},
		"LocalTime": {"2019-01-20"},
		"ZeroValue": {},
		"CSTTime":   {"2019-01-20"},
		"UTCTime":   {"2019-01-20"},
	})
	require.NoError(t, err)

	assert.Equal(t, "2019-01-20 16:02:58 +0000 UTC", s.Time.String())
	assert.Equal(t, "2019-01-20 00:00:00 +0100 CET", s.LocalTime.String())
	assert.Equal(t, "2019-01-19 23:00:00 +0000 UTC", s.LocalTime.UTC().String())
	assert.Equal(t, "0001-01-01 00:00:00 +0000 UTC", s.ZeroValue.String())
	assert.Equal(t, "2019-01-20 00:00:00 +0800 CST", s.CSTTime.String())
	assert.Equal(t, "2019-01-19 16:00:00 +0000 UTC", s.CSTTime.UTC().String())
	assert.Equal(t, "2019-01-20 00:00:00 +0000 UTC", s.UTCTime.String())

	// wrong location
	var wrongLoc struct {
		Time time.Time `time_location:"wrong"`
	}
	err = mapForm(&wrongLoc, map[string][]string{"Time": {"2019-01-20T16:02:58Z"}})
	require.Error(t, err)

	// wrong time value
	var wrongTime struct {
		Time time.Time
	}
	err = mapForm(&wrongTime, map[string][]string{"Time": {"wrong"}})
	require.Error(t, err)
}

type bindTestData struct {
	need any
	got  any
	in   map[string][]string
}

func TestMappingTimeUnixNano(t *testing.T) {
	type needFixUnixNanoEmpty struct {
		CreateTime time.Time `form:"createTime" time_format:"unixNano"`
	}

	// ok
	tests := []bindTestData{
		{need: &needFixUnixNanoEmpty{}, got: &needFixUnixNanoEmpty{}, in: formSource{"createTime": []string{"   "}}},
		{need: &needFixUnixNanoEmpty{}, got: &needFixUnixNanoEmpty{}, in: formSource{"createTime": []string{}}},
	}

	for _, v := range tests {
		err := mapForm(v.got, v.in)
		require.NoError(t, err)
		assert.Equal(t, v.need, v.got)
	}
}

func TestMappingTimeDuration(t *testing.T) {
	type needFixDurationEmpty struct {
		Duration time.Duration `form:"duration"`
	}

	var s struct {
		D time.Duration
	}

	// ok
	err := mappingByPtr(&s, formSource{"D": {"5s"}}, "form")
	require.NoError(t, err)
	assert.Equal(t, 5*time.Second, s.D)

	// ok
	tests := []bindTestData{
		{need: &needFixDurationEmpty{}, got: &needFixDurationEmpty{}, in: formSource{"duration": []string{"   "}}},
		{need: &needFixDurationEmpty{}, got: &needFixDurationEmpty{}, in: formSource{"duration": []string{}}},
	}

	for _, v := range tests {
		err := mapForm(v.got, v.in)
		require.NoError(t, err)
		assert.Equal(t, v.need, v.got)
	}
	// error
	err = mappingByPtr(&s, formSource{"D": {"wrong"}}, "form")
	require.Error(t, err)
}

func TestMappingSlice(t *testing.T) {
	var s struct {
		Slice []int `form:"slice,default=9"`
	}

	// default value
	err := mappingByPtr(&s, formSource{}, "form")
	require.NoError(t, err)
	assert.Equal(t, []int{9}, s.Slice)

	// ok
	err = mappingByPtr(&s, formSource{"slice": {"3", "4"}}, "form")
	require.NoError(t, err)
	assert.Equal(t, []int{3, 4}, s.Slice)

	// error
	err = mappingByPtr(&s, formSource{"slice": {"wrong"}}, "form")
	require.Error(t, err)
}

func TestMappingArray(t *testing.T) {
	var s struct {
		Array [2]int `form:"array,default=9"`
	}

	// wrong default
	err := mappingByPtr(&s, formSource{}, "form")
	require.Error(t, err)

	// ok
	err = mappingByPtr(&s, formSource{"array": {"3", "4"}}, "form")
	require.NoError(t, err)
	assert.Equal(t, [2]int{3, 4}, s.Array)

	// error - not enough vals
	err = mappingByPtr(&s, formSource{"array": {"3"}}, "form")
	require.Error(t, err)

	// error - wrong value
	err = mappingByPtr(&s, formSource{"array": {"wrong"}}, "form")
	require.Error(t, err)
}

func TestMappingCollectionFormat(t *testing.T) {
	var s struct {
		SliceMulti []int  `form:"slice_multi" collection_format:"multi"`
		SliceCsv   []int  `form:"slice_csv" collection_format:"csv"`
		SliceSsv   []int  `form:"slice_ssv" collection_format:"ssv"`
		SliceTsv   []int  `form:"slice_tsv" collection_format:"tsv"`
		SlicePipes []int  `form:"slice_pipes" collection_format:"pipes"`
		ArrayMulti [2]int `form:"array_multi" collection_format:"multi"`
		ArrayCsv   [2]int `form:"array_csv" collection_format:"csv"`
		ArraySsv   [2]int `form:"array_ssv" collection_format:"ssv"`
		ArrayTsv   [2]int `form:"array_tsv" collection_format:"tsv"`
		ArrayPipes [2]int `form:"array_pipes" collection_format:"pipes"`
	}
	err := mappingByPtr(&s, formSource{
		"slice_multi": {"1", "2"},
		"slice_csv":   {"1,2"},
		"slice_ssv":   {"1 2"},
		"slice_tsv":   {"1	2"},
		"slice_pipes": {"1|2"},
		"array_multi": {"1", "2"},
		"array_csv":   {"1,2"},
		"array_ssv":   {"1 2"},
		"array_tsv":   {"1	2"},
		"array_pipes": {"1|2"},
	}, "form")
	require.NoError(t, err)

	assert.Equal(t, []int{1, 2}, s.SliceMulti)
	assert.Equal(t, []int{1, 2}, s.SliceCsv)
	assert.Equal(t, []int{1, 2}, s.SliceSsv)
	assert.Equal(t, []int{1, 2}, s.SliceTsv)
	assert.Equal(t, []int{1, 2}, s.SlicePipes)
	assert.Equal(t, [2]int{1, 2}, s.ArrayMulti)
	assert.Equal(t, [2]int{1, 2}, s.ArrayCsv)
	assert.Equal(t, [2]int{1, 2}, s.ArraySsv)
	assert.Equal(t, [2]int{1, 2}, s.ArrayTsv)
	assert.Equal(t, [2]int{1, 2}, s.ArrayPipes)
}

func TestMappingCollectionFormatInvalid(t *testing.T) {
	var s struct {
		SliceCsv []int `form:"slice_csv" collection_format:"xxx"`
	}
	err := mappingByPtr(&s, formSource{
		"slice_csv": {"1,2"},
	}, "form")
	require.Error(t, err)

	var s2 struct {
		ArrayCsv [2]int `form:"array_csv" collection_format:"xxx"`
	}
	err = mappingByPtr(&s2, formSource{
		"array_csv": {"1,2"},
	}, "form")
	require.Error(t, err)
}

func TestMappingMultipleDefaultWithCollectionFormat(t *testing.T) {
	var s struct {
		SliceMulti       []int     `form:",default=1;2;3" collection_format:"multi"`
		SliceCsv         []int     `form:",default=1;2;3" collection_format:"csv"`
		SliceSsv         []int     `form:",default=1 2 3" collection_format:"ssv"`
		SliceTsv         []int     `form:",default=1\t2\t3" collection_format:"tsv"`
		SlicePipes       []int     `form:",default=1|2|3" collection_format:"pipes"`
		ArrayMulti       [2]int    `form:",default=1;2" collection_format:"multi"`
		ArrayCsv         [2]int    `form:",default=1;2" collection_format:"csv"`
		ArraySsv         [2]int    `form:",default=1 2" collection_format:"ssv"`
		ArrayTsv         [2]int    `form:",default=1\t2" collection_format:"tsv"`
		ArrayPipes       [2]int    `form:",default=1|2" collection_format:"pipes"`
		SliceStringMulti []string  `form:",default=1;2;3" collection_format:"multi"`
		SliceStringCsv   []string  `form:",default=1;2;3" collection_format:"csv"`
		SliceStringSsv   []string  `form:",default=1 2 3" collection_format:"ssv"`
		SliceStringTsv   []string  `form:",default=1\t2\t3" collection_format:"tsv"`
		SliceStringPipes []string  `form:",default=1|2|3" collection_format:"pipes"`
		ArrayStringMulti [2]string `form:",default=1;2" collection_format:"multi"`
		ArrayStringCsv   [2]string `form:",default=1;2" collection_format:"csv"`
		ArrayStringSsv   [2]string `form:",default=1 2" collection_format:"ssv"`
		ArrayStringTsv   [2]string `form:",default=1\t2" collection_format:"tsv"`
		ArrayStringPipes [2]string `form:",default=1|2" collection_format:"pipes"`
	}
	err := mappingByPtr(&s, formSource{}, "form")
	require.NoError(t, err)

	assert.Equal(t, []int{1, 2, 3}, s.SliceMulti)
	assert.Equal(t, []int{1, 2, 3}, s.SliceCsv)
	assert.Equal(t, []int{1, 2, 3}, s.SliceSsv)
	assert.Equal(t, []int{1, 2, 3}, s.SliceTsv)
	assert.Equal(t, []int{1, 2, 3}, s.SlicePipes)
	assert.Equal(t, [2]int{1, 2}, s.ArrayMulti)
	assert.Equal(t, [2]int{1, 2}, s.ArrayCsv)
	assert.Equal(t, [2]int{1, 2}, s.ArraySsv)
	assert.Equal(t, [2]int{1, 2}, s.ArrayTsv)
	assert.Equal(t, [2]int{1, 2}, s.ArrayPipes)
	assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringMulti)
	assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringCsv)
	assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringSsv)
	assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringTsv)
	assert.Equal(t, []string{"1", "2", "3"}, s.SliceStringPipes)
	assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringMulti)
	assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringCsv)
	assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringSsv)
	assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringTsv)
	assert.Equal(t, [2]string{"1", "2"}, s.ArrayStringPipes)
}

func TestMappingStructField(t *testing.T) {
	var s struct {
		J struct {
			I int
		}
	}

	err := mappingByPtr(&s, formSource{"J": {`{"I": 9}`}}
Download .txt
gitextract_g5woqams/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.yaml
│   │   ├── config.yml
│   │   └── feature-request.yaml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── codeql.yml
│       ├── gin.yml
│       ├── goreleaser.yml
│       └── trivy-scan.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yaml
├── BENCHMARKS.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── auth.go
├── auth_test.go
├── benchmarks_test.go
├── binding/
│   ├── binding.go
│   ├── binding_msgpack_test.go
│   ├── binding_nomsgpack.go
│   ├── binding_test.go
│   ├── bson.go
│   ├── default_validator.go
│   ├── default_validator_benchmark_test.go
│   ├── default_validator_test.go
│   ├── form.go
│   ├── form_mapping.go
│   ├── form_mapping_benchmark_test.go
│   ├── form_mapping_test.go
│   ├── header.go
│   ├── json.go
│   ├── json_test.go
│   ├── msgpack.go
│   ├── msgpack_test.go
│   ├── multipart_form_mapping.go
│   ├── multipart_form_mapping_test.go
│   ├── plain.go
│   ├── protobuf.go
│   ├── query.go
│   ├── toml.go
│   ├── toml_test.go
│   ├── uri.go
│   ├── validate_test.go
│   ├── xml.go
│   ├── xml_test.go
│   ├── yaml.go
│   └── yaml_test.go
├── codec/
│   └── json/
│       ├── api.go
│       ├── go_json.go
│       ├── json.go
│       ├── jsoniter.go
│       └── sonic.go
├── codecov.yml
├── context.go
├── context_appengine.go
├── context_file_test.go
├── context_test.go
├── debug.go
├── debug_test.go
├── deprecated.go
├── deprecated_test.go
├── doc.go
├── docs/
│   └── doc.md
├── errors.go
├── errors_test.go
├── examples/
│   └── README.md
├── fs.go
├── fs_test.go
├── gin.go
├── ginS/
│   ├── README.md
│   ├── gins.go
│   └── gins_test.go
├── gin_integration_test.go
├── gin_test.go
├── githubapi_test.go
├── go.mod
├── go.sum
├── internal/
│   ├── bytesconv/
│   │   ├── bytesconv.go
│   │   └── bytesconv_test.go
│   └── fs/
│       ├── fs.go
│       └── fs_test.go
├── logger.go
├── logger_test.go
├── middleware_test.go
├── mode.go
├── mode_test.go
├── path.go
├── path_test.go
├── recovery.go
├── recovery_test.go
├── render/
│   ├── bson.go
│   ├── data.go
│   ├── html.go
│   ├── json.go
│   ├── msgpack.go
│   ├── pdf.go
│   ├── protobuf.go
│   ├── reader.go
│   ├── reader_test.go
│   ├── redirect.go
│   ├── render.go
│   ├── render_msgpack_test.go
│   ├── render_test.go
│   ├── text.go
│   ├── toml.go
│   ├── xml.go
│   └── yaml.go
├── response_writer.go
├── response_writer_test.go
├── routergroup.go
├── routergroup_test.go
├── routes_test.go
├── test_helpers.go
├── testdata/
│   ├── certificate/
│   │   ├── cert.pem
│   │   └── key.pem
│   ├── protoexample/
│   │   ├── test.pb.go
│   │   └── test.proto
│   ├── template/
│   │   ├── hello.tmpl
│   │   └── raw.tmpl
│   └── test_file.txt
├── tree.go
├── tree_test.go
├── utils.go
├── utils_test.go
└── version.go
Download .txt
SYMBOL INDEX (1590 symbols across 98 files)

FILE: auth.go
  constant AuthUserKey (line 17) | AuthUserKey = "user"
  constant AuthProxyUserKey (line 20) | AuthProxyUserKey = "proxy_user"
  type Accounts (line 23) | type Accounts
  type authPair (line 25) | type authPair struct
  type authPairs (line 30) | type authPairs
    method searchCredential (line 32) | func (a authPairs) searchCredential(authValue string) (string, bool) {
  function BasicAuthForRealm (line 48) | func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
  function BasicAuth (line 72) | func BasicAuth(accounts Accounts) HandlerFunc {
  function processAccounts (line 76) | func processAccounts(accounts Accounts) authPairs {
  function authorizationHeader (line 91) | func authorizationHeader(user, password string) string {
  function BasicAuthForProxy (line 98) | func BasicAuthForProxy(accounts Accounts, realm string) HandlerFunc {

FILE: auth_test.go
  function TestBasicAuth (line 16) | func TestBasicAuth(t *testing.T) {
  function TestBasicAuthFails (line 38) | func TestBasicAuthFails(t *testing.T) {
  function TestBasicAuthSearchCredential (line 48) | func TestBasicAuthSearchCredential(t *testing.T) {
  function TestBasicAuthAuthorizationHeader (line 80) | func TestBasicAuthAuthorizationHeader(t *testing.T) {
  function TestBasicAuthSucceed (line 84) | func TestBasicAuthSucceed(t *testing.T) {
  function TestBasicAuth401 (line 101) | func TestBasicAuth401(t *testing.T) {
  function TestBasicAuth401WithCustomRealm (line 121) | func TestBasicAuth401WithCustomRealm(t *testing.T) {
  function TestBasicAuthForProxySucceed (line 141) | func TestBasicAuthForProxySucceed(t *testing.T) {
  function TestBasicAuthForProxy407 (line 158) | func TestBasicAuthForProxy407(t *testing.T) {

FILE: benchmarks_test.go
  function BenchmarkOneRoute (line 14) | func BenchmarkOneRoute(B *testing.B) {
  function BenchmarkRecoveryMiddleware (line 20) | func BenchmarkRecoveryMiddleware(B *testing.B) {
  function BenchmarkLoggerMiddleware (line 27) | func BenchmarkLoggerMiddleware(B *testing.B) {
  function BenchmarkManyHandlers (line 34) | func BenchmarkManyHandlers(B *testing.B) {
  function Benchmark5Params (line 43) | func Benchmark5Params(B *testing.B) {
  function BenchmarkOneRouteJSON (line 51) | func BenchmarkOneRouteJSON(B *testing.B) {
  function BenchmarkOneRouteHTML (line 62) | func BenchmarkOneRouteHTML(B *testing.B) {
  function BenchmarkOneRouteSet (line 74) | func BenchmarkOneRouteSet(B *testing.B) {
  function BenchmarkOneRouteString (line 82) | func BenchmarkOneRouteString(B *testing.B) {
  function BenchmarkManyRoutesFirst (line 90) | func BenchmarkManyRoutesFirst(B *testing.B) {
  function BenchmarkManyRoutesLast (line 96) | func BenchmarkManyRoutesLast(B *testing.B) {
  function Benchmark404 (line 102) | func Benchmark404(B *testing.B) {
  function Benchmark404Many (line 109) | func Benchmark404Many(B *testing.B) {
  type mockWriter (line 124) | type mockWriter struct
    method Header (line 134) | func (m *mockWriter) Header() (h http.Header) {
    method Write (line 138) | func (m *mockWriter) Write(p []byte) (n int, err error) {
    method WriteString (line 142) | func (m *mockWriter) WriteString(s string) (n int, err error) {
    method WriteHeader (line 146) | func (m *mockWriter) WriteHeader(int) {}
  function newMockWriter (line 128) | func newMockWriter() *mockWriter {
  function runRequest (line 148) | func runRequest(B *testing.B, r *Engine, method, path string) {

FILE: binding/binding.go
  constant MIMEJSON (line 13) | MIMEJSON              = "application/json"
  constant MIMEHTML (line 14) | MIMEHTML              = "text/html"
  constant MIMEXML (line 15) | MIMEXML               = "application/xml"
  constant MIMEXML2 (line 16) | MIMEXML2              = "text/xml"
  constant MIMEPlain (line 17) | MIMEPlain             = "text/plain"
  constant MIMEPOSTForm (line 18) | MIMEPOSTForm          = "application/x-www-form-urlencoded"
  constant MIMEMultipartPOSTForm (line 19) | MIMEMultipartPOSTForm = "multipart/form-data"
  constant MIMEPROTOBUF (line 20) | MIMEPROTOBUF          = "application/x-protobuf"
  constant MIMEMSGPACK (line 21) | MIMEMSGPACK           = "application/x-msgpack"
  constant MIMEMSGPACK2 (line 22) | MIMEMSGPACK2          = "application/msgpack"
  constant MIMEYAML (line 23) | MIMEYAML              = "application/x-yaml"
  constant MIMEYAML2 (line 24) | MIMEYAML2             = "application/yaml"
  constant MIMETOML (line 25) | MIMETOML              = "application/toml"
  constant MIMEBSON (line 26) | MIMEBSON              = "application/bson"
  type Binding (line 32) | type Binding interface
  type BindingBody (line 39) | type BindingBody interface
  type BindingUri (line 46) | type BindingUri interface
  type StructValidator (line 55) | type StructValidator interface
  function Default (line 95) | func Default(method, contentType string) Binding {
  function validate (line 122) | func validate(obj any) error {

FILE: binding/binding_msgpack_test.go
  function TestBindingMsgPack (line 19) | func TestBindingMsgPack(t *testing.T) {
  function testMsgPackBodyBinding (line 39) | func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath...
  function TestBindingDefaultMsgPack (line 56) | func TestBindingDefaultMsgPack(t *testing.T) {

FILE: binding/binding_nomsgpack.go
  constant MIMEJSON (line 13) | MIMEJSON              = "application/json"
  constant MIMEHTML (line 14) | MIMEHTML              = "text/html"
  constant MIMEXML (line 15) | MIMEXML               = "application/xml"
  constant MIMEXML2 (line 16) | MIMEXML2              = "text/xml"
  constant MIMEPlain (line 17) | MIMEPlain             = "text/plain"
  constant MIMEPOSTForm (line 18) | MIMEPOSTForm          = "application/x-www-form-urlencoded"
  constant MIMEMultipartPOSTForm (line 19) | MIMEMultipartPOSTForm = "multipart/form-data"
  constant MIMEPROTOBUF (line 20) | MIMEPROTOBUF          = "application/x-protobuf"
  constant MIMEYAML (line 21) | MIMEYAML              = "application/x-yaml"
  constant MIMEYAML2 (line 22) | MIMEYAML2             = "application/yaml"
  constant MIMETOML (line 23) | MIMETOML              = "application/toml"
  constant MIMEBSON (line 24) | MIMEBSON              = "application/bson"
  type Binding (line 30) | type Binding interface
  type BindingBody (line 37) | type BindingBody interface
  type BindingUri (line 44) | type BindingUri interface
  type StructValidator (line 53) | type StructValidator interface
  function Default (line 91) | func Default(method, contentType string) Binding {
  function validate (line 116) | func validate(obj any) error {

FILE: binding/binding_test.go
  type appkey (line 28) | type appkey struct
  type QueryTest (line 32) | type QueryTest struct
  type FooStruct (line 38) | type FooStruct struct
  type FooBarStruct (line 42) | type FooBarStruct struct
  type FooBarFileStruct (line 47) | type FooBarFileStruct struct
  type FooBarFileFailStruct (line 52) | type FooBarFileFailStruct struct
  type FooDefaultBarStruct (line 57) | type FooDefaultBarStruct struct
  type FooStructUseNumber (line 62) | type FooStructUseNumber struct
  type FooStructDisallowUnknownFields (line 66) | type FooStructDisallowUnknownFields struct
  type FooBarStructForTimeType (line 70) | type FooBarStructForTimeType struct
  type FooStructForTimeTypeNotUnixFormat (line 79) | type FooStructForTimeTypeNotUnixFormat struct
  type FooStructForTimeTypeNotFormat (line 86) | type FooStructForTimeTypeNotFormat struct
  type FooStructForTimeTypeFailFormat (line 90) | type FooStructForTimeTypeFailFormat struct
  type FooStructForTimeTypeFailLocation (line 94) | type FooStructForTimeTypeFailLocation struct
  type FooStructForMapType (line 98) | type FooStructForMapType struct
  type FooStructForIgnoreFormTag (line 102) | type FooStructForIgnoreFormTag struct
  type InvalidNameType (line 106) | type InvalidNameType struct
  type InvalidNameMapType (line 110) | type InvalidNameMapType struct
  type FooStructForSliceType (line 116) | type FooStructForSliceType struct
  type FooStructForStructType (line 120) | type FooStructForStructType struct
  type FooStructForStructPointerType (line 126) | type FooStructForStructPointerType struct
  type FooStructForSliceMapType (line 132) | type FooStructForSliceMapType struct
  type FooStructForBoolType (line 137) | type FooStructForBoolType struct
  type FooStructForStringPtrType (line 141) | type FooStructForStringPtrType struct
  type FooStructForMapPtrType (line 146) | type FooStructForMapPtrType struct
  function TestBindingDefault (line 150) | func TestBindingDefault(t *testing.T) {
  function TestBindingJSONNilBody (line 181) | func TestBindingJSONNilBody(t *testing.T) {
  function TestBindingJSON (line 188) | func TestBindingJSON(t *testing.T) {
  function TestBindingJSONSlice (line 195) | func TestBindingJSONSlice(t *testing.T) {
  function TestBindingJSONUseNumber (line 209) | func TestBindingJSONUseNumber(t *testing.T) {
  function TestBindingJSONUseNumber2 (line 216) | func TestBindingJSONUseNumber2(t *testing.T) {
  function TestBindingJSONDisallowUnknownFields (line 223) | func TestBindingJSONDisallowUnknownFields(t *testing.T) {
  function TestBindingJSONStringMap (line 229) | func TestBindingJSONStringMap(t *testing.T) {
  function TestBindingForm (line 235) | func TestBindingForm(t *testing.T) {
  function TestBindingForm2 (line 241) | func TestBindingForm2(t *testing.T) {
  function TestBindingFormEmbeddedStruct (line 247) | func TestBindingFormEmbeddedStruct(t *testing.T) {
  function TestBindingFormEmbeddedStruct2 (line 253) | func TestBindingFormEmbeddedStruct2(t *testing.T) {
  function TestBindingFormDefaultValue (line 259) | func TestBindingFormDefaultValue(t *testing.T) {
  function TestBindingFormDefaultValue2 (line 265) | func TestBindingFormDefaultValue2(t *testing.T) {
  function TestBindingFormForTime (line 271) | func TestBindingFormForTime(t *testing.T) {
  function TestBindingFormForTime2 (line 289) | func TestBindingFormForTime2(t *testing.T) {
  function TestFormBindingIgnoreField (line 307) | func TestFormBindingIgnoreField(t *testing.T) {
  function TestBindingFormInvalidName (line 313) | func TestBindingFormInvalidName(t *testing.T) {
  function TestBindingFormInvalidName2 (line 319) | func TestBindingFormInvalidName2(t *testing.T) {
  function TestBindingFormForType (line 325) | func TestBindingFormForType(t *testing.T) {
  function TestBindingFormStringMap (line 371) | func TestBindingFormStringMap(t *testing.T) {
  function TestBindingFormStringSliceMap (line 381) | func TestBindingFormStringSliceMap(t *testing.T) {
  function TestBindingQuery (line 402) | func TestBindingQuery(t *testing.T) {
  function TestBindingQuery2 (line 408) | func TestBindingQuery2(t *testing.T) {
  function TestBindingQueryFail (line 414) | func TestBindingQueryFail(t *testing.T) {
  function TestBindingQueryFail2 (line 420) | func TestBindingQueryFail2(t *testing.T) {
  function TestBindingQueryBoolFail (line 426) | func TestBindingQueryBoolFail(t *testing.T) {
  function TestBindingQueryStringMap (line 432) | func TestBindingQueryStringMap(t *testing.T) {
  function TestBindingXML (line 454) | func TestBindingXML(t *testing.T) {
  function TestBindingXMLFail (line 461) | func TestBindingXMLFail(t *testing.T) {
  function TestBindingTOML (line 468) | func TestBindingTOML(t *testing.T) {
  function TestBindingTOMLFail (line 475) | func TestBindingTOMLFail(t *testing.T) {
  function TestBindingYAML (line 482) | func TestBindingYAML(t *testing.T) {
  function TestBindingYAMLStringMap (line 489) | func TestBindingYAMLStringMap(t *testing.T) {
  function TestBindingYAMLFail (line 496) | func TestBindingYAMLFail(t *testing.T) {
  function createFormPostRequest (line 503) | func createFormPostRequest(t *testing.T) *http.Request {
  function createDefaultFormPostRequest (line 510) | func createDefaultFormPostRequest(t *testing.T) *http.Request {
  function createFormPostRequestForMap (line 517) | func createFormPostRequestForMap(t *testing.T) *http.Request {
  function createFormPostRequestForMapFail (line 524) | func createFormPostRequestForMapFail(t *testing.T) *http.Request {
  function createFormFilesMultipartRequest (line 531) | func createFormFilesMultipartRequest(t *testing.T) *http.Request {
  function createFormFilesMultipartRequestFail (line 556) | func createFormFilesMultipartRequestFail(t *testing.T) *http.Request {
  function createFormMultipartRequest (line 581) | func createFormMultipartRequest(t *testing.T) *http.Request {
  function createFormMultipartRequestForMap (line 596) | func createFormMultipartRequestForMap(t *testing.T) *http.Request {
  function createFormMultipartRequestForMapFail (line 610) | func createFormMultipartRequestForMapFail(t *testing.T) *http.Request {
  function TestBindingFormPost (line 624) | func TestBindingFormPost(t *testing.T) {
  function TestBindingDefaultValueFormPost (line 634) | func TestBindingDefaultValueFormPost(t *testing.T) {
  function TestBindingFormPostForMap (line 643) | func TestBindingFormPostForMap(t *testing.T) {
  function TestBindingFormPostForMapFail (line 651) | func TestBindingFormPostForMapFail(t *testing.T) {
  function TestBindingFormFilesMultipart (line 658) | func TestBindingFormFilesMultipart(t *testing.T) {
  function TestBindingFormFilesMultipartFail (line 680) | func TestBindingFormFilesMultipartFail(t *testing.T) {
  function TestBindingFormMultipart (line 687) | func TestBindingFormMultipart(t *testing.T) {
  function TestBindingFormMultipartForMap (line 697) | func TestBindingFormMultipartForMap(t *testing.T) {
  function TestBindingFormMultipartForMapFail (line 707) | func TestBindingFormMultipartForMapFail(t *testing.T) {
  function TestBindingProtoBuf (line 714) | func TestBindingProtoBuf(t *testing.T) {
  function TestBindingProtoBufFail (line 726) | func TestBindingProtoBufFail(t *testing.T) {
  function TestBindingBSON (line 738) | func TestBindingBSON(t *testing.T) {
  function TestValidationFails (line 750) | func TestValidationFails(t *testing.T) {
  function TestValidationDisabled (line 757) | func TestValidationDisabled(t *testing.T) {
  function TestRequiredSucceeds (line 768) | func TestRequiredSucceeds(t *testing.T) {
  function TestRequiredFails (line 779) | func TestRequiredFails(t *testing.T) {
  function TestHeaderBinding (line 790) | func TestHeaderBinding(t *testing.T) {
  function TestUriBinding (line 815) | func TestUriBinding(t *testing.T) {
  function TestUriInnerBinding (line 836) | func TestUriInnerBinding(t *testing.T) {
  function testFormBindingEmbeddedStruct (line 858) | func testFormBindingEmbeddedStruct(t *testing.T, method, path, badPath, ...
  function testFormBinding (line 874) | func testFormBinding(t *testing.T, method, path, badPath, body, badBody ...
  function testFormBindingDefaultValue (line 894) | func testFormBindingDefaultValue(t *testing.T, method, path, badPath, bo...
  function TestFormBindingFail (line 914) | func TestFormBindingFail(t *testing.T) {
  function TestFormBindingMultipartFail (line 924) | func TestFormBindingMultipartFail(t *testing.T) {
  function TestFormPostBindingFail (line 935) | func TestFormPostBindingFail(t *testing.T) {
  function TestFormMultipartBindingFail (line 945) | func TestFormMultipartBindingFail(t *testing.T) {
  function testFormBindingForTime (line 955) | func testFormBindingForTime(t *testing.T, method, path, badPath, body, b...
  function testFormBindingForTimeNotUnixFormat (line 982) | func testFormBindingForTimeNotUnixFormat(t *testing.T, method, path, bad...
  function testFormBindingForTimeNotFormat (line 1000) | func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath...
  function testFormBindingForTimeFailFormat (line 1018) | func testFormBindingForTimeFailFormat(t *testing.T, method, path, badPat...
  function testFormBindingForTimeFailLocation (line 1036) | func testFormBindingForTimeFailLocation(t *testing.T, method, path, badP...
  function testFormBindingIgnoreField (line 1054) | func testFormBindingIgnoreField(t *testing.T, method, path, badPath, bod...
  function testFormBindingInvalidName (line 1069) | func testFormBindingInvalidName(t *testing.T, method, path, badPath, bod...
  function testFormBindingInvalidName2 (line 1088) | func testFormBindingInvalidName2(t *testing.T, method, path, badPath, bo...
  function testFormBindingForType (line 1106) | func testFormBindingForType(t *testing.T, method, path, badPath, body, b...
  function testQueryBinding (line 1176) | func testQueryBinding(t *testing.T, method, path, badPath, body, badBody...
  function testQueryBindingFail (line 1191) | func testQueryBindingFail(t *testing.T, method, path, badPath, body, bad...
  function testQueryBindingBoolFail (line 1204) | func testQueryBindingBoolFail(t *testing.T, method, path, badPath, body,...
  function testBodyBinding (line 1217) | func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body,...
  function testBodyBindingSlice (line 1232) | func testBodyBindingSlice(t *testing.T, b Binding, name, path, badPath, ...
  function testBodyBindingStringMap (line 1246) | func testBodyBindingStringMap(t *testing.T, b Binding, path, badPath, bo...
  function testBodyBindingUseNumber (line 1272) | func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPa...
  function testBodyBindingUseNumber2 (line 1291) | func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badP...
  function testBodyBindingDisallowUnknownFields (line 1309) | func testBodyBindingDisallowUnknownFields(t *testing.T, b Binding, path,...
  function testBodyBindingFail (line 1328) | func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, b...
  function testProtoBodyBinding (line 1343) | func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, ...
  type hook (line 1360) | type hook struct
    method Read (line 1362) | func (h hook) Read([]byte) (int, error) {
  type failRead (line 1366) | type failRead struct
    method Read (line 1368) | func (f *failRead) Read(b []byte) (n int, err error) {
    method Close (line 1372) | func (f *failRead) Close() error {
  function TestPlainBinding (line 1376) | func TestPlainBinding(t *testing.T) {
  function testProtoBodyBindingFail (line 1406) | func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPa...
  function requestWithBody (line 1431) | func requestWithBody(method, path, body string) (req *http.Request) {

FILE: binding/bson.go
  type bsonBinding (line 14) | type bsonBinding struct
    method Name (line 16) | func (bsonBinding) Name() string {
    method Bind (line 20) | func (b bsonBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 28) | func (bsonBinding) BindBody(body []byte, obj any) error {

FILE: binding/default_validator.go
  type defaultValidator (line 16) | type defaultValidator struct
    method ValidateStruct (line 44) | func (v *defaultValidator) ValidateStruct(obj any) error {
    method validateStruct (line 76) | func (v *defaultValidator) validateStruct(obj any) error {
    method Engine (line 85) | func (v *defaultValidator) Engine() any {
    method lazyinit (line 90) | func (v *defaultValidator) lazyinit() {
  type SliceValidationError (line 21) | type SliceValidationError
    method Error (line 24) | func (err SliceValidationError) Error() string {

FILE: binding/default_validator_benchmark_test.go
  function BenchmarkSliceValidationError (line 13) | func BenchmarkSliceValidationError(b *testing.B) {

FILE: binding/default_validator_test.go
  function TestSliceValidationError (line 12) | func TestSliceValidationError(t *testing.T) {
  function TestDefaultValidator (line 51) | func TestDefaultValidator(t *testing.T) {

FILE: binding/form.go
  constant defaultMemory (line 12) | defaultMemory = 32 << 20
  type formBinding (line 15) | type formBinding struct
    method Name (line 20) | func (formBinding) Name() string {
    method Bind (line 24) | func (formBinding) Bind(req *http.Request, obj any) error {
  type formPostBinding (line 16) | type formPostBinding struct
    method Name (line 37) | func (formPostBinding) Name() string {
    method Bind (line 41) | func (formPostBinding) Bind(req *http.Request, obj any) error {
  type formMultipartBinding (line 17) | type formMultipartBinding struct
    method Name (line 51) | func (formMultipartBinding) Name() string {
    method Bind (line 55) | func (formMultipartBinding) Bind(req *http.Request, obj any) error {

FILE: binding/form_mapping.go
  function mapURI (line 32) | func mapURI(ptr any, m map[string][]string) error {
  function mapForm (line 36) | func mapForm(ptr any, form map[string][]string) error {
  function MapFormWithTag (line 40) | func MapFormWithTag(ptr any, form map[string][]string, tag string) error {
  function mapFormByTag (line 46) | func mapFormByTag(ptr any, form map[string][]string, tag string) error {
  type setter (line 66) | type setter interface
  type formSource (line 70) | type formSource
    method TrySet (line 75) | func (form formSource) TrySet(value reflect.Value, field reflect.Struc...
  function mappingByPtr (line 79) | func mappingByPtr(ptr any, setter setter, tag string) error {
  function mapping (line 84) | func mapping(value reflect.Value, field reflect.StructField, setter sett...
  type setOptions (line 138) | type setOptions struct
  function tryToSetValue (line 145) | func tryToSetValue(value reflect.Value, field reflect.StructField, sette...
  type BindUnmarshaler (line 183) | type BindUnmarshaler interface
  function trySetCustom (line 191) | func trySetCustom(val string, value reflect.Value) (isSet bool, err erro...
  function trySetUsingParser (line 201) | func trySetUsingParser(val string, value reflect.Value, parser string) (...
  function trySplit (line 213) | func trySplit(vs []string, field reflect.StructField) (newVs []string, e...
  function setByForm (line 245) | func setByForm(value reflect.Value, field reflect.StructField, form map[...
  function setWithProperType (line 323) | func setWithProperType(val string, value reflect.Value, field reflect.St...
  function setIntField (line 390) | func setIntField(val string, bitSize int, field reflect.Value) error {
  function setUintField (line 401) | func setUintField(val string, bitSize int, field reflect.Value) error {
  function setBoolField (line 412) | func setBoolField(val string, field reflect.Value) error {
  function setFloatField (line 423) | func setFloatField(val string, bitSize int, field reflect.Value) error {
  function setTimeField (line 434) | func setTimeField(val string, structField reflect.StructField, value ref...
  function setArray (line 490) | func setArray(vals []string, value reflect.Value, field reflect.StructFi...
  function setSlice (line 500) | func setSlice(vals []string, value reflect.Value, field reflect.StructFi...
  function setTimeDuration (line 510) | func setTimeDuration(val string, value reflect.Value) error {
  function head (line 523) | func head(str, sep string) (head string, tail string) {
  function setFormMap (line 528) | func setFormMap(ptr any, form map[string][]string) error {

FILE: binding/form_mapping_benchmark_test.go
  type structFull (line 21) | type structFull struct
  function BenchmarkMapFormFull (line 32) | func BenchmarkMapFormFull(b *testing.B) {
  type structName (line 51) | type structName struct
  function BenchmarkMapFormName (line 55) | func BenchmarkMapFormName(b *testing.B) {

FILE: binding/form_mapping_test.go
  function TestMappingBaseTypes (line 22) | func TestMappingBaseTypes(t *testing.T) {
  function TestMappingDefault (line 71) | func TestMappingDefault(t *testing.T) {
  function TestMappingSkipField (line 87) | func TestMappingSkipField(t *testing.T) {
  function TestMappingIgnoreField (line 97) | func TestMappingIgnoreField(t *testing.T) {
  function TestMappingUnexportedField (line 109) | func TestMappingUnexportedField(t *testing.T) {
  function TestMappingPrivateField (line 121) | func TestMappingPrivateField(t *testing.T) {
  function TestMappingUnknownFieldType (line 130) | func TestMappingUnknownFieldType(t *testing.T) {
  function TestMappingURI (line 140) | func TestMappingURI(t *testing.T) {
  function TestMappingForm (line 149) | func TestMappingForm(t *testing.T) {
  function TestMappingFormFieldNotSent (line 158) | func TestMappingFormFieldNotSent(t *testing.T) {
  function TestMappingFormWithEmptyToDefault (line 167) | func TestMappingFormWithEmptyToDefault(t *testing.T) {
  function TestMapFormWithTag (line 176) | func TestMapFormWithTag(t *testing.T) {
  function TestMappingTime (line 185) | func TestMappingTime(t *testing.T) {
  type bindTestData (line 230) | type bindTestData struct
  function TestMappingTimeUnixNano (line 236) | func TestMappingTimeUnixNano(t *testing.T) {
  function TestMappingTimeDuration (line 254) | func TestMappingTimeDuration(t *testing.T) {
  function TestMappingSlice (line 284) | func TestMappingSlice(t *testing.T) {
  function TestMappingArray (line 304) | func TestMappingArray(t *testing.T) {
  function TestMappingCollectionFormat (line 327) | func TestMappingCollectionFormat(t *testing.T) {
  function TestMappingCollectionFormatInvalid (line 366) | func TestMappingCollectionFormatInvalid(t *testing.T) {
  function TestMappingMultipleDefaultWithCollectionFormat (line 384) | func TestMappingMultipleDefaultWithCollectionFormat(t *testing.T) {
  function TestMappingStructField (line 432) | func TestMappingStructField(t *testing.T) {
  function TestMappingPtrField (line 444) | func TestMappingPtrField(t *testing.T) {
  function TestMappingMapField (line 477) | func TestMappingMapField(t *testing.T) {
  function TestMappingIgnoredCircularRef (line 487) | func TestMappingIgnoredCircularRef(t *testing.T) {
  type customUnmarshalParamHex (line 497) | type customUnmarshalParamHex
    method UnmarshalParam (line 499) | func (f *customUnmarshalParamHex) UnmarshalParam(param string) error {
  function TestMappingCustomUnmarshalParamHexWithFormTag (line 508) | func TestMappingCustomUnmarshalParamHexWithFormTag(t *testing.T) {
  function TestMappingCustomUnmarshalParamHexWithURITag (line 518) | func TestMappingCustomUnmarshalParamHexWithURITag(t *testing.T) {
  function TestMappingCustomUnmarshalParamHexDefault (line 528) | func TestMappingCustomUnmarshalParamHexDefault(t *testing.T) {
  type customUnmarshalParamType (line 538) | type customUnmarshalParamType struct
    method UnmarshalParam (line 544) | func (f *customUnmarshalParamType) UnmarshalParam(param string) error {
  function TestMappingCustomStructTypeWithFormTag (line 555) | func TestMappingCustomStructTypeWithFormTag(t *testing.T) {
  function TestMappingCustomStructTypeWithURITag (line 567) | func TestMappingCustomStructTypeWithURITag(t *testing.T) {
  function TestMappingCustomPointerStructTypeWithFormTag (line 579) | func TestMappingCustomPointerStructTypeWithFormTag(t *testing.T) {
  function TestMappingCustomPointerStructTypeWithURITag (line 591) | func TestMappingCustomPointerStructTypeWithURITag(t *testing.T) {
  type customPath (line 603) | type customPath
    method UnmarshalParam (line 605) | func (p *customPath) UnmarshalParam(param string) error {
  function TestMappingCustomSliceUri (line 616) | func TestMappingCustomSliceUri(t *testing.T) {
  function TestMappingCustomSliceForm (line 627) | func TestMappingCustomSliceForm(t *testing.T) {
  function TestMappingCustomSliceStopsWhenError (line 638) | func TestMappingCustomSliceStopsWhenError(t *testing.T) {
  function TestMappingCustomSliceOfSliceUri (line 647) | func TestMappingCustomSliceOfSliceUri(t *testing.T) {
  function TestMappingCustomSliceOfSliceForm (line 656) | func TestMappingCustomSliceOfSliceForm(t *testing.T) {
  type objectID (line 665) | type objectID
    method UnmarshalParam (line 667) | func (o *objectID) UnmarshalParam(param string) error {
  function convertTo (line 677) | func convertTo(s string) (objectID, error) {
  function TestMappingCustomArrayUri (line 692) | func TestMappingCustomArrayUri(t *testing.T) {
  function TestMappingCustomArrayForm (line 704) | func TestMappingCustomArrayForm(t *testing.T) {
  function TestMappingCustomArrayOfArrayUri (line 716) | func TestMappingCustomArrayOfArrayUri(t *testing.T) {
  function TestMappingCustomArrayOfArrayForm (line 728) | func TestMappingCustomArrayOfArrayForm(t *testing.T) {
  type customUnmarshalTextHex (line 742) | type customUnmarshalTextHex
    method UnmarshalText (line 744) | func (f *customUnmarshalTextHex) UnmarshalText(text []byte) error {
  function TestMappingCustomUnmarshalTextHexUri (line 756) | func TestMappingCustomUnmarshalTextHexUri(t *testing.T) {
  function TestMappingCustomUnmarshalTextHexForm (line 765) | func TestMappingCustomUnmarshalTextHexForm(t *testing.T) {
  function TestMappingCustomUnmarshalTextHexDefault (line 774) | func TestMappingCustomUnmarshalTextHexDefault(t *testing.T) {
  type customUnmarshalTextType (line 783) | type customUnmarshalTextType struct
    method UnmarshalText (line 789) | func (f *customUnmarshalTextType) UnmarshalText(text []byte) error {
  function TestMappingCustomStructTypeUnmarshalTextForm (line 802) | func TestMappingCustomStructTypeUnmarshalTextForm(t *testing.T) {
  function TestMappingCustomStructTypeUnmarshalTextUri (line 814) | func TestMappingCustomStructTypeUnmarshalTextUri(t *testing.T) {
  function TestMappingCustomPointerStructTypeUnmarshalTextForm (line 826) | func TestMappingCustomPointerStructTypeUnmarshalTextForm(t *testing.T) {
  function TestMappingCustomPointerStructTypeUnmarshalTextUri (line 838) | func TestMappingCustomPointerStructTypeUnmarshalTextUri(t *testing.T) {
  type customPathUnmarshalText (line 850) | type customPathUnmarshalText
    method UnmarshalText (line 852) | func (p *customPathUnmarshalText) UnmarshalText(text []byte) error {
  function TestMappingCustomSliceUnmarshalTextUri (line 865) | func TestMappingCustomSliceUnmarshalTextUri(t *testing.T) {
  function TestMappingCustomSliceUnmarshalTextForm (line 876) | func TestMappingCustomSliceUnmarshalTextForm(t *testing.T) {
  function TestMappingCustomSliceUnmarshalTextStopsWhenError (line 887) | func TestMappingCustomSliceUnmarshalTextStopsWhenError(t *testing.T) {
  function TestMappingCustomSliceOfSliceUnmarshalTextUri (line 896) | func TestMappingCustomSliceOfSliceUnmarshalTextUri(t *testing.T) {
  function TestMappingCustomSliceOfSliceUnmarshalTextForm (line 905) | func TestMappingCustomSliceOfSliceUnmarshalTextForm(t *testing.T) {
  function TestMappingCustomSliceOfSliceUnmarshalTextDefault (line 914) | func TestMappingCustomSliceOfSliceUnmarshalTextDefault(t *testing.T) {
  type objectIDUnmarshalText (line 923) | type objectIDUnmarshalText
    method UnmarshalText (line 925) | func (o *objectIDUnmarshalText) UnmarshalText(text []byte) error {
  function convertToOidUnmarshalText (line 935) | func convertToOidUnmarshalText(s string) (objectIDUnmarshalText, error) {
  function TestMappingCustomArrayUnmarshalTextUri (line 942) | func TestMappingCustomArrayUnmarshalTextUri(t *testing.T) {
  function TestMappingCustomArrayUnmarshalTextForm (line 954) | func TestMappingCustomArrayUnmarshalTextForm(t *testing.T) {
  function TestMappingCustomArrayOfArrayUnmarshalTextUri (line 966) | func TestMappingCustomArrayOfArrayUnmarshalTextUri(t *testing.T) {
  function TestMappingCustomArrayOfArrayUnmarshalTextForm (line 978) | func TestMappingCustomArrayOfArrayUnmarshalTextForm(t *testing.T) {
  function TestMappingCustomArrayOfArrayUnmarshalTextDefault (line 990) | func TestMappingCustomArrayOfArrayUnmarshalTextDefault(t *testing.T) {
  function TestMappingUsingBindUnmarshalerAndTextUnmarshalerWhenOnlyBindUnmarshalerDefined (line 1004) | func TestMappingUsingBindUnmarshalerAndTextUnmarshalerWhenOnlyBindUnmars...
  function TestMappingUsingBindUnmarshalerAndTextUnmarshalerWhenOnlyTextUnmarshalerDefined (line 1022) | func TestMappingUsingBindUnmarshalerAndTextUnmarshalerWhenOnlyTextUnmars...
  type customHexUnmarshalParamAndUnmarshalText (line 1037) | type customHexUnmarshalParamAndUnmarshalText
    method UnmarshalParam (line 1039) | func (f *customHexUnmarshalParamAndUnmarshalText) UnmarshalParam(param...
    method UnmarshalText (line 1043) | func (f *customHexUnmarshalParamAndUnmarshalText) UnmarshalText(text [...
  function TestMappingUsingTextUnmarshalerWhenBindUnmarshalerAlsoDefined (line 1054) | func TestMappingUsingTextUnmarshalerWhenBindUnmarshalerAlsoDefined(t *te...
  function TestMappingEmptyValues (line 1068) | func TestMappingEmptyValues(t *testing.T) {

FILE: binding/header.go
  type headerBinding (line 13) | type headerBinding struct
    method Name (line 15) | func (headerBinding) Name() string {
    method Bind (line 19) | func (headerBinding) Bind(req *http.Request, obj any) error {
  function mapHeader (line 27) | func mapHeader(ptr any, h map[string][]string) error {
  type headerSource (line 31) | type headerSource
    method TrySet (line 35) | func (hs headerSource) TrySet(value reflect.Value, field reflect.Struc...

FILE: binding/json.go
  type jsonBinding (line 27) | type jsonBinding struct
    method Name (line 29) | func (jsonBinding) Name() string {
    method Bind (line 33) | func (jsonBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 40) | func (jsonBinding) BindBody(body []byte, obj any) error {
  function decodeJSON (line 44) | func decodeJSON(r io.Reader, obj any) error {

FILE: binding/json_test.go
  function TestJSONBindingBindBody (line 22) | func TestJSONBindingBindBody(t *testing.T) {
  function TestJSONBindingBindBodyMap (line 31) | func TestJSONBindingBindBodyMap(t *testing.T) {
  function TestCustomJsonCodec (line 40) | func TestCustomJsonCodec(t *testing.T) {
  type customReq (line 65) | type customReq struct
  function init (line 78) | func init() {
  type customJsonApi (line 83) | type customJsonApi struct
    method Marshal (line 85) | func (j customJsonApi) Marshal(v any) ([]byte, error) {
    method Unmarshal (line 89) | func (j customJsonApi) Unmarshal(data []byte, v any) error {
    method MarshalIndent (line 93) | func (j customJsonApi) MarshalIndent(v any, prefix, indent string) ([]...
    method NewEncoder (line 97) | func (j customJsonApi) NewEncoder(writer io.Writer) json.Encoder {
    method NewDecoder (line 101) | func (j customJsonApi) NewDecoder(reader io.Reader) json.Decoder {
  type TimeEx (line 113) | type TimeEx struct
    method CreateDecoder (line 117) | func (te *TimeEx) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
    method CreateEncoder (line 124) | func (te *TimeEx) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
  type timeCodec (line 131) | type timeCodec struct
    method IsEmpty (line 133) | func (tc timeCodec) IsEmpty(ptr unsafe.Pointer) bool {
    method Encode (line 138) | func (tc timeCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
    method Decode (line 147) | func (tc timeCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
  type TimePointerEx (line 169) | type TimePointerEx struct
    method CreateDecoder (line 173) | func (tpe *TimePointerEx) CreateDecoder(typ reflect2.Type) jsoniter.Va...
    method CreateEncoder (line 180) | func (tpe *TimePointerEx) CreateEncoder(typ reflect2.Type) jsoniter.Va...
  type timePointerCodec (line 187) | type timePointerCodec struct
    method IsEmpty (line 189) | func (tpc timePointerCodec) IsEmpty(ptr unsafe.Pointer) bool {
    method Encode (line 194) | func (tpc timePointerCodec) Encode(ptr unsafe.Pointer, stream *jsonite...
    method Decode (line 203) | func (tpc timePointerCodec) Decode(ptr unsafe.Pointer, iter *jsoniter....

FILE: binding/msgpack.go
  type msgpackBinding (line 17) | type msgpackBinding struct
    method Name (line 19) | func (msgpackBinding) Name() string {
    method Bind (line 23) | func (msgpackBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 27) | func (msgpackBinding) BindBody(body []byte, obj any) error {
  function decodeMsgPack (line 31) | func decodeMsgPack(r io.Reader, obj any) error {

FILE: binding/msgpack_test.go
  function TestMsgpackBindingBindBody (line 18) | func TestMsgpackBindingBindBody(t *testing.T) {
  function msgpackBody (line 28) | func msgpackBody(t *testing.T, obj any) []byte {

FILE: binding/multipart_form_mapping.go
  type multipartRequest (line 14) | type multipartRequest
    method TrySet (line 27) | func (r *multipartRequest) TrySet(value reflect.Value, field reflect.S...
  function setByMultipartFormFile (line 35) | func setByMultipartFormFile(value reflect.Value, field reflect.StructFie...
  function setArrayOfMultipartFormFiles (line 63) | func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.Str...

FILE: binding/multipart_form_mapping_test.go
  function TestFormMultipartBindingBindOneFile (line 18) | func TestFormMultipartBindingBindOneFile(t *testing.T) {
  function TestFormMultipartBindingBindTwoFiles (line 43) | func TestFormMultipartBindingBindTwoFiles(t *testing.T) {
  function TestFormMultipartBindingBindError (line 72) | func TestFormMultipartBindingBindError(t *testing.T) {
  type testFile (line 98) | type testFile struct
  function createRequestMultipartFiles (line 104) | func createRequestMultipartFiles(t *testing.T, files ...testFile) *http....
  function assertMultipartFileHeader (line 126) | func assertMultipartFileHeader(t *testing.T, fh *multipart.FileHeader, f...

FILE: binding/plain.go
  type plainBinding (line 12) | type plainBinding struct
    method Name (line 14) | func (plainBinding) Name() string {
    method Bind (line 18) | func (plainBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 27) | func (plainBinding) BindBody(body []byte, obj any) error {
  function decodePlain (line 31) | func decodePlain(data []byte, obj any) error {

FILE: binding/protobuf.go
  type protobufBinding (line 15) | type protobufBinding struct
    method Name (line 17) | func (protobufBinding) Name() string {
    method Bind (line 21) | func (b protobufBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 29) | func (protobufBinding) BindBody(body []byte, obj any) error {

FILE: binding/query.go
  type queryBinding (line 9) | type queryBinding struct
    method Name (line 11) | func (queryBinding) Name() string {
    method Bind (line 15) | func (queryBinding) Bind(req *http.Request, obj any) error {

FILE: binding/toml.go
  type tomlBinding (line 15) | type tomlBinding struct
    method Name (line 17) | func (tomlBinding) Name() string {
    method Bind (line 21) | func (tomlBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 25) | func (tomlBinding) BindBody(body []byte, obj any) error {
  function decodeToml (line 29) | func decodeToml(r io.Reader, obj any) error {

FILE: binding/toml_test.go
  function TestTOMLBindingBindBody (line 14) | func TestTOMLBindingBindBody(t *testing.T) {

FILE: binding/uri.go
  type uriBinding (line 7) | type uriBinding struct
    method Name (line 9) | func (uriBinding) Name() string {
    method BindUri (line 13) | func (uriBinding) BindUri(m map[string][]string, obj any) error {

FILE: binding/validate_test.go
  type testInterface (line 17) | type testInterface interface
  type substructNoValidation (line 21) | type substructNoValidation struct
  type mapNoValidationSub (line 26) | type mapNoValidationSub
  type structNoValidationValues (line 28) | type structNoValidationValues struct
  function createNoValidationValues (line 70) | func createNoValidationValues() structNoValidationValues {
  function TestValidateNoValidationValues (line 112) | func TestValidateNoValidationValues(t *testing.T) {
  type structNoValidationPointer (line 125) | type structNoValidationPointer struct
  function TestValidateNoValidationPointers (line 160) | func TestValidateNoValidationPointers(t *testing.T) {
  type Object (line 173) | type Object
  function TestValidatePrimitives (line 175) | func TestValidatePrimitives(t *testing.T) {
  type structModifyValidation (line 196) | type structModifyValidation struct
  function toZero (line 200) | func toZero(sl validator.StructLevel) {
  function TestValidateAndModifyStruct (line 205) | func TestValidateAndModifyStruct(t *testing.T) {
  type structCustomValidation (line 223) | type structCustomValidation struct
  function notOne (line 227) | func notOne(f1 validator.FieldLevel) bool {
  function TestValidatorEngine (line 234) | func TestValidatorEngine(t *testing.T) {

FILE: binding/xml.go
  type xmlBinding (line 14) | type xmlBinding struct
    method Name (line 16) | func (xmlBinding) Name() string {
    method Bind (line 20) | func (xmlBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 24) | func (xmlBinding) BindBody(body []byte, obj any) error {
  function decodeXML (line 28) | func decodeXML(r io.Reader, obj any) error {

FILE: binding/xml_test.go
  function TestXMLBindingBindBody (line 14) | func TestXMLBindingBindBody(t *testing.T) {

FILE: binding/yaml.go
  type yamlBinding (line 15) | type yamlBinding struct
    method Name (line 17) | func (yamlBinding) Name() string {
    method Bind (line 21) | func (yamlBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 25) | func (yamlBinding) BindBody(body []byte, obj any) error {
  function decodeYAML (line 29) | func decodeYAML(r io.Reader, obj any) error {

FILE: binding/yaml_test.go
  function TestYAMLBindingBindBody (line 14) | func TestYAMLBindingBindBody(t *testing.T) {

FILE: codec/json/api.go
  type Core (line 13) | type Core interface
  type Encoder (line 22) | type Encoder interface
  type Decoder (line 41) | type Decoder interface

FILE: codec/json/go_json.go
  constant Package (line 16) | Package = "github.com/goccy/go-json"
  function init (line 18) | func init() {
  type gojsonApi (line 22) | type gojsonApi struct
    method Marshal (line 24) | func (j gojsonApi) Marshal(v any) ([]byte, error) {
    method Unmarshal (line 28) | func (j gojsonApi) Unmarshal(data []byte, v any) error {
    method MarshalIndent (line 32) | func (j gojsonApi) MarshalIndent(v any, prefix, indent string) ([]byte...
    method NewEncoder (line 36) | func (j gojsonApi) NewEncoder(writer io.Writer) Encoder {
    method NewDecoder (line 40) | func (j gojsonApi) NewDecoder(reader io.Reader) Decoder {

FILE: codec/json/json.go
  constant Package (line 15) | Package = "encoding/json"
  function init (line 17) | func init() {
  type jsonApi (line 21) | type jsonApi struct
    method Marshal (line 23) | func (j jsonApi) Marshal(v any) ([]byte, error) {
    method Unmarshal (line 27) | func (j jsonApi) Unmarshal(data []byte, v any) error {
    method MarshalIndent (line 31) | func (j jsonApi) MarshalIndent(v any, prefix, indent string) ([]byte, ...
    method NewEncoder (line 35) | func (j jsonApi) NewEncoder(writer io.Writer) Encoder {
    method NewDecoder (line 39) | func (j jsonApi) NewDecoder(reader io.Reader) Decoder {

FILE: codec/json/jsoniter.go
  constant Package (line 16) | Package = "github.com/json-iterator/go"
  function init (line 18) | func init() {
  type jsoniterApi (line 24) | type jsoniterApi struct
    method Marshal (line 26) | func (j jsoniterApi) Marshal(v any) ([]byte, error) {
    method Unmarshal (line 30) | func (j jsoniterApi) Unmarshal(data []byte, v any) error {
    method MarshalIndent (line 34) | func (j jsoniterApi) MarshalIndent(v any, prefix, indent string) ([]by...
    method NewEncoder (line 38) | func (j jsoniterApi) NewEncoder(writer io.Writer) Encoder {
    method NewDecoder (line 42) | func (j jsoniterApi) NewDecoder(reader io.Reader) Decoder {

FILE: codec/json/sonic.go
  constant Package (line 16) | Package = "github.com/bytedance/sonic"
  function init (line 18) | func init() {
  type sonicApi (line 24) | type sonicApi struct
    method Marshal (line 26) | func (j sonicApi) Marshal(v any) ([]byte, error) {
    method Unmarshal (line 30) | func (j sonicApi) Unmarshal(data []byte, v any) error {
    method MarshalIndent (line 34) | func (j sonicApi) MarshalIndent(v any, prefix, indent string) ([]byte,...
    method NewEncoder (line 38) | func (j sonicApi) NewEncoder(writer io.Writer) Encoder {
    method NewDecoder (line 42) | func (j sonicApi) NewDecoder(reader io.Reader) Decoder {

FILE: context.go
  constant MIMEJSON (line 32) | MIMEJSON              = binding.MIMEJSON
  constant MIMEHTML (line 33) | MIMEHTML              = binding.MIMEHTML
  constant MIMEXML (line 34) | MIMEXML               = binding.MIMEXML
  constant MIMEXML2 (line 35) | MIMEXML2              = binding.MIMEXML2
  constant MIMEPlain (line 36) | MIMEPlain             = binding.MIMEPlain
  constant MIMEPOSTForm (line 37) | MIMEPOSTForm          = binding.MIMEPOSTForm
  constant MIMEMultipartPOSTForm (line 38) | MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
  constant MIMEYAML (line 39) | MIMEYAML              = binding.MIMEYAML
  constant MIMEYAML2 (line 40) | MIMEYAML2             = binding.MIMEYAML2
  constant MIMETOML (line 41) | MIMETOML              = binding.MIMETOML
  constant MIMEPROTOBUF (line 42) | MIMEPROTOBUF          = binding.MIMEPROTOBUF
  constant MIMEBSON (line 43) | MIMEBSON              = binding.MIMEBSON
  constant BodyBytesKey (line 47) | BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
  constant ContextKey (line 50) | ContextKey = "_gin-gonic/gin/contextkey"
  type ContextKeyType (line 52) | type ContextKeyType
  constant ContextRequestKey (line 54) | ContextRequestKey ContextKeyType = 0
  constant abortIndex (line 57) | abortIndex int8 = math.MaxInt8 >> 1
  type Context (line 61) | type Context struct
    method reset (line 103) | func (c *Context) reset() {
    method Copy (line 122) | func (c *Context) Copy() *Context {
    method HandlerName (line 149) | func (c *Context) HandlerName() string {
    method HandlerNames (line 155) | func (c *Context) HandlerNames() []string {
    method Handler (line 167) | func (c *Context) Handler() HandlerFunc {
    method FullPath (line 177) | func (c *Context) FullPath() string {
    method Next (line 188) | func (c *Context) Next() {
    method IsAborted (line 199) | func (c *Context) IsAborted() bool {
    method Abort (line 207) | func (c *Context) Abort() {
    method AbortWithStatus (line 213) | func (c *Context) AbortWithStatus(code int) {
    method AbortWithStatusPureJSON (line 222) | func (c *Context) AbortWithStatusPureJSON(code int, jsonObj any) {
    method AbortWithStatusJSON (line 230) | func (c *Context) AbortWithStatusJSON(code int, jsonObj any) {
    method AbortWithError (line 238) | func (c *Context) AbortWithError(code int, err error) *Error {
    method Error (line 252) | func (c *Context) Error(err error) *Error {
    method Set (line 276) | func (c *Context) Set(key any, value any) {
    method Get (line 288) | func (c *Context) Get(key any) (value any, exists bool) {
    method MustGet (line 296) | func (c *Context) MustGet(key any) any {
    method GetString (line 311) | func (c *Context) GetString(key any) string {
    method GetBool (line 316) | func (c *Context) GetBool(key any) bool {
    method GetInt (line 321) | func (c *Context) GetInt(key any) int {
    method GetInt8 (line 326) | func (c *Context) GetInt8(key any) int8 {
    method GetInt16 (line 331) | func (c *Context) GetInt16(key any) int16 {
    method GetInt32 (line 336) | func (c *Context) GetInt32(key any) int32 {
    method GetInt64 (line 341) | func (c *Context) GetInt64(key any) int64 {
    method GetUint (line 346) | func (c *Context) GetUint(key any) uint {
    method GetUint8 (line 351) | func (c *Context) GetUint8(key any) uint8 {
    method GetUint16 (line 356) | func (c *Context) GetUint16(key any) uint16 {
    method GetUint32 (line 361) | func (c *Context) GetUint32(key any) uint32 {
    method GetUint64 (line 366) | func (c *Context) GetUint64(key any) uint64 {
    method GetFloat32 (line 371) | func (c *Context) GetFloat32(key any) float32 {
    method GetFloat64 (line 376) | func (c *Context) GetFloat64(key any) float64 {
    method GetTime (line 381) | func (c *Context) GetTime(key any) time.Time {
    method GetDuration (line 386) | func (c *Context) GetDuration(key any) time.Duration {
    method GetError (line 391) | func (c *Context) GetError(key any) error {
    method GetIntSlice (line 396) | func (c *Context) GetIntSlice(key any) []int {
    method GetInt8Slice (line 401) | func (c *Context) GetInt8Slice(key any) []int8 {
    method GetInt16Slice (line 406) | func (c *Context) GetInt16Slice(key any) []int16 {
    method GetInt32Slice (line 411) | func (c *Context) GetInt32Slice(key any) []int32 {
    method GetInt64Slice (line 416) | func (c *Context) GetInt64Slice(key any) []int64 {
    method GetUintSlice (line 421) | func (c *Context) GetUintSlice(key any) []uint {
    method GetUint8Slice (line 426) | func (c *Context) GetUint8Slice(key any) []uint8 {
    method GetUint16Slice (line 431) | func (c *Context) GetUint16Slice(key any) []uint16 {
    method GetUint32Slice (line 436) | func (c *Context) GetUint32Slice(key any) []uint32 {
    method GetUint64Slice (line 441) | func (c *Context) GetUint64Slice(key any) []uint64 {
    method GetFloat32Slice (line 446) | func (c *Context) GetFloat32Slice(key any) []float32 {
    method GetFloat64Slice (line 451) | func (c *Context) GetFloat64Slice(key any) []float64 {
    method GetStringSlice (line 456) | func (c *Context) GetStringSlice(key any) []string {
    method GetErrorSlice (line 461) | func (c *Context) GetErrorSlice(key any) []error {
    method GetStringMap (line 466) | func (c *Context) GetStringMap(key any) map[string]any {
    method GetStringMapString (line 471) | func (c *Context) GetStringMapString(key any) map[string]string {
    method GetStringMapStringSlice (line 476) | func (c *Context) GetStringMapStringSlice(key any) map[string][]string {
    method Delete (line 482) | func (c *Context) Delete(key any) {
    method Param (line 503) | func (c *Context) Param(key string) string {
    method AddParam (line 512) | func (c *Context) AddParam(key, value string) {
    method Query (line 525) | func (c *Context) Query(key string) (value string) {
    method DefaultQuery (line 538) | func (c *Context) DefaultQuery(key, defaultValue string) string {
    method GetQuery (line 554) | func (c *Context) GetQuery(key string) (string, bool) {
    method QueryArray (line 563) | func (c *Context) QueryArray(key string) (values []string) {
    method initQueryCache (line 568) | func (c *Context) initQueryCache() {
    method GetQueryArray (line 580) | func (c *Context) GetQueryArray(key string) (values []string, ok bool) {
    method QueryMap (line 587) | func (c *Context) QueryMap(key string) (dicts map[string]string) {
    method GetQueryMap (line 594) | func (c *Context) GetQueryMap(key string) (map[string]string, bool) {
    method PostForm (line 601) | func (c *Context) PostForm(key string) (value string) {
    method DefaultPostForm (line 609) | func (c *Context) DefaultPostForm(key, defaultValue string) string {
    method GetPostForm (line 624) | func (c *Context) GetPostForm(key string) (string, bool) {
    method PostFormArray (line 633) | func (c *Context) PostFormArray(key string) (values []string) {
    method initFormCache (line 638) | func (c *Context) initFormCache() {
    method GetPostFormArray (line 653) | func (c *Context) GetPostFormArray(key string) (values []string, ok bo...
    method PostFormMap (line 660) | func (c *Context) PostFormMap(key string) (dicts map[string]string) {
    method GetPostFormMap (line 667) | func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
    method FormFile (line 698) | func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
    method MultipartForm (line 713) | func (c *Context) MultipartForm() (*multipart.Form, error) {
    method SaveUploadedFile (line 719) | func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst str...
    method Bind (line 757) | func (c *Context) Bind(obj any) error {
    method BindJSON (line 763) | func (c *Context) BindJSON(obj any) error {
    method BindXML (line 768) | func (c *Context) BindXML(obj any) error {
    method BindQuery (line 773) | func (c *Context) BindQuery(obj any) error {
    method BindYAML (line 778) | func (c *Context) BindYAML(obj any) error {
    method BindTOML (line 783) | func (c *Context) BindTOML(obj any) error {
    method BindPlain (line 788) | func (c *Context) BindPlain(obj any) error {
    method BindHeader (line 793) | func (c *Context) BindHeader(obj any) error {
    method BindUri (line 799) | func (c *Context) BindUri(obj any) error {
    method MustBindWith (line 810) | func (c *Context) MustBindWith(obj any, b binding.Binding) error {
    method ShouldBind (line 838) | func (c *Context) ShouldBind(obj any) error {
    method ShouldBindJSON (line 867) | func (c *Context) ShouldBindJSON(obj any) error {
    method ShouldBindXML (line 873) | func (c *Context) ShouldBindXML(obj any) error {
    method ShouldBindQuery (line 879) | func (c *Context) ShouldBindQuery(obj any) error {
    method ShouldBindYAML (line 885) | func (c *Context) ShouldBindYAML(obj any) error {
    method ShouldBindTOML (line 891) | func (c *Context) ShouldBindTOML(obj any) error {
    method ShouldBindPlain (line 897) | func (c *Context) ShouldBindPlain(obj any) error {
    method ShouldBindHeader (line 903) | func (c *Context) ShouldBindHeader(obj any) error {
    method ShouldBindUri (line 909) | func (c *Context) ShouldBindUri(obj any) error {
    method ShouldBindWith (line 919) | func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
    method ShouldBindBodyWith (line 928) | func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) ...
    method ShouldBindBodyWithJSON (line 946) | func (c *Context) ShouldBindBodyWithJSON(obj any) error {
    method ShouldBindBodyWithXML (line 951) | func (c *Context) ShouldBindBodyWithXML(obj any) error {
    method ShouldBindBodyWithYAML (line 956) | func (c *Context) ShouldBindBodyWithYAML(obj any) error {
    method ShouldBindBodyWithTOML (line 961) | func (c *Context) ShouldBindBodyWithTOML(obj any) error {
    method ShouldBindBodyWithPlain (line 966) | func (c *Context) ShouldBindBodyWithPlain(obj any) error {
    method ClientIP (line 975) | func (c *Context) ClientIP() string {
    method RemoteIP (line 1027) | func (c *Context) RemoteIP() string {
    method ContentType (line 1036) | func (c *Context) ContentType() string {
    method IsWebsocket (line 1042) | func (c *Context) IsWebsocket() bool {
    method requestHeader (line 1050) | func (c *Context) requestHeader(key string) string {
    method Status (line 1073) | func (c *Context) Status(code int) {
    method Header (line 1080) | func (c *Context) Header(key, value string) {
    method GetHeader (line 1089) | func (c *Context) GetHeader(key string) string {
    method GetRawData (line 1094) | func (c *Context) GetRawData() ([]byte, error) {
    method SetSameSite (line 1102) | func (c *Context) SetSameSite(samesite http.SameSite) {
    method SetCookie (line 1109) | func (c *Context) SetCookie(name, value string, maxAge int, path, doma...
    method SetCookieData (line 1128) | func (c *Context) SetCookieData(cookie *http.Cookie) {
    method Cookie (line 1142) | func (c *Context) Cookie(name string) (string, error) {
    method Render (line 1152) | func (c *Context) Render(code int, r render.Render) {
    method HTML (line 1171) | func (c *Context) HTML(code int, name string, obj any) {
    method IndentedJSON (line 1180) | func (c *Context) IndentedJSON(code int, obj any) {
    method SecureJSON (line 1187) | func (c *Context) SecureJSON(code int, obj any) {
    method JSONP (line 1194) | func (c *Context) JSONP(code int, obj any) {
    method JSON (line 1205) | func (c *Context) JSON(code int, obj any) {
    method AsciiJSON (line 1211) | func (c *Context) AsciiJSON(code int, obj any) {
    method PureJSON (line 1217) | func (c *Context) PureJSON(code int, obj any) {
    method XML (line 1223) | func (c *Context) XML(code int, obj any) {
    method PDF (line 1229) | func (c *Context) PDF(code int, data []byte) {
    method YAML (line 1234) | func (c *Context) YAML(code int, obj any) {
    method TOML (line 1239) | func (c *Context) TOML(code int, obj any) {
    method ProtoBuf (line 1244) | func (c *Context) ProtoBuf(code int, obj any) {
    method BSON (line 1249) | func (c *Context) BSON(code int, obj any) {
    method String (line 1254) | func (c *Context) String(code int, format string, values ...any) {
    method Redirect (line 1259) | func (c *Context) Redirect(code int, location string) {
    method Data (line 1268) | func (c *Context) Data(code int, contentType string, data []byte) {
    method DataFromReader (line 1276) | func (c *Context) DataFromReader(code int, contentLength int64, conten...
    method File (line 1286) | func (c *Context) File(filepath string) {
    method FileFromFS (line 1291) | func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
    method FileAttachment (line 1309) | func (c *Context) FileAttachment(filepath, filename string) {
    method SSEvent (line 1319) | func (c *Context) SSEvent(name string, message any) {
    method Stream (line 1328) | func (c *Context) Stream(step func(w io.Writer) bool) bool {
    method Negotiate (line 1364) | func (c *Context) Negotiate(code int, config Negotiate) {
    method NegotiateFormat (line 1400) | func (c *Context) NegotiateFormat(offered ...string) string {
    method SetAccepted (line 1431) | func (c *Context) SetAccepted(formats ...string) {
    method hasRequestContext (line 1440) | func (c *Context) hasRequestContext() bool {
    method Deadline (line 1447) | func (c *Context) Deadline() (deadline time.Time, ok bool) {
    method Done (line 1455) | func (c *Context) Done() <-chan struct{} {
    method Err (line 1463) | func (c *Context) Err() error {
    method Value (line 1473) | func (c *Context) Value(key any) any {
  function getTyped (line 303) | func getTyped[T any](c *Context, key any) (res T) {
  function getMapFromFormData (line 674) | func getMapFromFormData(m map[string][]string, key string) (map[string]s...
  function bodyAllowedForStatus (line 1060) | func bodyAllowedForStatus(status int) bool {
  function escapeQuotes (line 1303) | func escapeQuotes(s string) string {
  type Negotiate (line 1350) | type Negotiate struct

FILE: context_appengine.go
  function init (line 9) | func init() {

FILE: context_file_test.go
  function TestContextFileSimple (line 12) | func TestContextFileSimple(t *testing.T) {
  function TestContextFileNotFound (line 27) | func TestContextFileNotFound(t *testing.T) {

FILE: context_test.go
  function createMultipartRequest (line 49) | func createMultipartRequest() *http.Request {
  function must (line 73) | func must(err error) {
  function TestContextFile (line 80) | func TestContextFile(t *testing.T) {
  function TestContextFormFile (line 152) | func TestContextFormFile(t *testing.T) {
  function TestContextFormFileFailed (line 170) | func TestContextFormFileFailed(t *testing.T) {
  function TestContextMultipartForm (line 183) | func TestContextMultipartForm(t *testing.T) {
  function TestSaveUploadedOpenFailed (line 202) | func TestSaveUploadedOpenFailed(t *testing.T) {
  function TestSaveUploadedCreateFailed (line 217) | func TestSaveUploadedCreateFailed(t *testing.T) {
  function TestSaveUploadedFileWithPermission (line 235) | func TestSaveUploadedFileWithPermission(t *testing.T) {
  function TestSaveUploadedFileWithPermissionFailed (line 259) | func TestSaveUploadedFileWithPermissionFailed(t *testing.T) {
  function TestContextReset (line 277) | func TestContextReset(t *testing.T) {
  function TestContextHandlers (line 300) | func TestContextHandlers(t *testing.T) {
  function TestContextSetGet (line 321) | func TestContextSetGet(t *testing.T) {
  function TestContextSetGetAnyKey (line 339) | func TestContextSetGetAnyKey(t *testing.T) {
  function TestContextSetGetPanicsWhenKeyNotComparable (line 366) | func TestContextSetGetPanicsWhenKeyNotComparable(t *testing.T) {
  function TestContextSetGetValues (line 376) | func TestContextSetGetValues(t *testing.T) {
  function TestContextGetString (line 396) | func TestContextGetString(t *testing.T) {
  function TestContextSetGetBool (line 402) | func TestContextSetGetBool(t *testing.T) {
  function TestSetGetDelete (line 408) | func TestSetGetDelete(t *testing.T) {
  function TestContextGetInt (line 421) | func TestContextGetInt(t *testing.T) {
  function TestContextGetInt8 (line 427) | func TestContextGetInt8(t *testing.T) {
  function TestContextGetInt16 (line 435) | func TestContextGetInt16(t *testing.T) {
  function TestContextGetInt32 (line 443) | func TestContextGetInt32(t *testing.T) {
  function TestContextGetInt64 (line 451) | func TestContextGetInt64(t *testing.T) {
  function TestContextGetUint (line 457) | func TestContextGetUint(t *testing.T) {
  function TestContextGetUint8 (line 463) | func TestContextGetUint8(t *testing.T) {
  function TestContextGetUint16 (line 471) | func TestContextGetUint16(t *testing.T) {
  function TestContextGetUint32 (line 479) | func TestContextGetUint32(t *testing.T) {
  function TestContextGetUint64 (line 487) | func TestContextGetUint64(t *testing.T) {
  function TestContextGetFloat32 (line 493) | func TestContextGetFloat32(t *testing.T) {
  function TestContextGetFloat64 (line 501) | func TestContextGetFloat64(t *testing.T) {
  function TestContextGetTime (line 507) | func TestContextGetTime(t *testing.T) {
  function TestContextGetDuration (line 514) | func TestContextGetDuration(t *testing.T) {
  function TestContextGetError (line 520) | func TestContextGetError(t *testing.T) {
  function TestContextGetIntSlice (line 528) | func TestContextGetIntSlice(t *testing.T) {
  function TestContextGetInt8Slice (line 536) | func TestContextGetInt8Slice(t *testing.T) {
  function TestContextGetInt16Slice (line 544) | func TestContextGetInt16Slice(t *testing.T) {
  function TestContextGetInt32Slice (line 552) | func TestContextGetInt32Slice(t *testing.T) {
  function TestContextGetInt64Slice (line 560) | func TestContextGetInt64Slice(t *testing.T) {
  function TestContextGetUintSlice (line 568) | func TestContextGetUintSlice(t *testing.T) {
  function TestContextGetUint8Slice (line 576) | func TestContextGetUint8Slice(t *testing.T) {
  function TestContextGetUint16Slice (line 584) | func TestContextGetUint16Slice(t *testing.T) {
  function TestContextGetUint32Slice (line 592) | func TestContextGetUint32Slice(t *testing.T) {
  function TestContextGetUint64Slice (line 600) | func TestContextGetUint64Slice(t *testing.T) {
  function TestContextGetFloat32Slice (line 608) | func TestContextGetFloat32Slice(t *testing.T) {
  function TestContextGetFloat64Slice (line 616) | func TestContextGetFloat64Slice(t *testing.T) {
  function TestContextGetStringSlice (line 624) | func TestContextGetStringSlice(t *testing.T) {
  function TestContextGetErrorSlice (line 630) | func TestContextGetErrorSlice(t *testing.T) {
  function TestContextGetStringMap (line 638) | func TestContextGetStringMap(t *testing.T) {
  function TestContextGetStringMapString (line 648) | func TestContextGetStringMapString(t *testing.T) {
  function TestContextGetStringMapStringSlice (line 658) | func TestContextGetStringMapStringSlice(t *testing.T) {
  function TestContextCopy (line 668) | func TestContextCopy(t *testing.T) {
  function TestContextHandlerName (line 691) | func TestContextHandlerName(t *testing.T) {
  function TestContextHandlerNames (line 698) | func TestContextHandlerNames(t *testing.T) {
  function handlerNameTest (line 710) | func handlerNameTest(c *Context) {
  function handlerNameTest2 (line 713) | func handlerNameTest2(c *Context) {
  function TestContextHandler (line 719) | func TestContextHandler(t *testing.T) {
  function TestContextQuery (line 726) | func TestContextQuery(t *testing.T) {
  function TestContextInitQueryCache (line 761) | func TestContextInitQueryCache(t *testing.T) {
  function TestContextDefaultQueryOnEmptyRequest (line 803) | func TestContextDefaultQueryOnEmptyRequest(t *testing.T) {
  function TestContextQueryAndPostForm (line 818) | func TestContextQueryAndPostForm(t *testing.T) {
  function TestContextPostFormMultipart (line 916) | func TestContextPostFormMultipart(t *testing.T) {
  function TestContextSetCookie (line 1008) | func TestContextSetCookie(t *testing.T) {
  function TestContextSetCookiePathEmpty (line 1015) | func TestContextSetCookiePathEmpty(t *testing.T) {
  function TestContextGetCookie (line 1022) | func TestContextGetCookie(t *testing.T) {
  function TestContextBodyAllowedForStatus (line 1033) | func TestContextBodyAllowedForStatus(t *testing.T) {
  type TestRender (line 1041) | type TestRender struct
    method Render (line 1043) | func (*TestRender) Render(http.ResponseWriter) error {
    method WriteContentType (line 1047) | func (*TestRender) WriteContentType(http.ResponseWriter) {}
  function TestContextRenderIfErr (line 1049) | func TestContextRenderIfErr(t *testing.T) {
  function TestContextRenderJSON (line 1061) | func TestContextRenderJSON(t *testing.T) {
  function TestContextRenderJSONP (line 1074) | func TestContextRenderJSONP(t *testing.T) {
  function TestContextRenderJSONPWithoutCallback (line 1088) | func TestContextRenderJSONPWithoutCallback(t *testing.T) {
  function TestContextRenderNoContentJSON (line 1101) | func TestContextRenderNoContentJSON(t *testing.T) {
  function TestContextRenderAPIJSON (line 1114) | func TestContextRenderAPIJSON(t *testing.T) {
  function TestContextRenderNoContentAPIJSON (line 1127) | func TestContextRenderNoContentAPIJSON(t *testing.T) {
  function TestContextRenderIndentedJSON (line 1141) | func TestContextRenderIndentedJSON(t *testing.T) {
  function TestContextRenderNoContentIndentedJSON (line 1153) | func TestContextRenderNoContentIndentedJSON(t *testing.T) {
  function TestContextClientIPWithMultipleHeaders (line 1164) | func TestContextClientIPWithMultipleHeaders(t *testing.T) {
  function TestContextClientIPWithSingleHeader (line 1181) | func TestContextClientIPWithSingleHeader(t *testing.T) {
  function TestContextRenderSecureJSON (line 1197) | func TestContextRenderSecureJSON(t *testing.T) {
  function TestContextRenderNoContentSecureJSON (line 1210) | func TestContextRenderNoContentSecureJSON(t *testing.T) {
  function TestContextRenderNoContentAsciiJSON (line 1221) | func TestContextRenderNoContentAsciiJSON(t *testing.T) {
  function TestContextRenderPureJSON (line 1235) | func TestContextRenderPureJSON(t *testing.T) {
  function TestContextRenderHTML (line 1246) | func TestContextRenderHTML(t *testing.T) {
  function TestContextRenderHTML2 (line 1260) | func TestContextRenderHTML2(t *testing.T) {
  function TestContextRenderNoContentHTML (line 1285) | func TestContextRenderNoContentHTML(t *testing.T) {
  function TestContextRenderXML (line 1300) | func TestContextRenderXML(t *testing.T) {
  function TestContextRenderNoContentXML (line 1312) | func TestContextRenderNoContentXML(t *testing.T) {
  function TestContextRenderPDF (line 1325) | func TestContextRenderPDF(t *testing.T) {
  function TestContextRenderNoContentPDF (line 1338) | func TestContextRenderNoContentPDF(t *testing.T) {
  function TestContextRenderString (line 1352) | func TestContextRenderString(t *testing.T) {
  function TestContextRenderNoContentString (line 1364) | func TestContextRenderNoContentString(t *testing.T) {
  function TestContextRenderHTMLString (line 1377) | func TestContextRenderHTMLString(t *testing.T) {
  function TestContextRenderNoContentHTMLString (line 1390) | func TestContextRenderNoContentHTMLString(t *testing.T) {
  function TestContextRenderData (line 1404) | func TestContextRenderData(t *testing.T) {
  function TestContextRenderNoContentData (line 1416) | func TestContextRenderNoContentData(t *testing.T) {
  function TestContextRenderSSE (line 1427) | func TestContextRenderSSE(t *testing.T) {
  function TestContextRenderFile (line 1444) | func TestContextRenderFile(t *testing.T) {
  function TestContextRenderFileFromFS (line 1458) | func TestContextRenderFileFromFS(t *testing.T) {
  function TestContextRenderAttachment (line 1473) | func TestContextRenderAttachment(t *testing.T) {
  function TestContextRenderAndEscapeAttachment (line 1486) | func TestContextRenderAndEscapeAttachment(t *testing.T) {
  function TestContextRenderUTF8Attachment (line 1500) | func TestContextRenderUTF8Attachment(t *testing.T) {
  function TestContextRenderYAML (line 1515) | func TestContextRenderYAML(t *testing.T) {
  function TestContextRenderTOML (line 1528) | func TestContextRenderTOML(t *testing.T) {
  function TestContextRenderProtoBuf (line 1542) | func TestContextRenderProtoBuf(t *testing.T) {
  function TestContextHeaders (line 1563) | func TestContextHeaders(t *testing.T) {
  function TestContextRenderRedirectWithRelativePath (line 1580) | func TestContextRenderRedirectWithRelativePath(t *testing.T) {
  function TestContextRenderRedirectWithAbsolutePath (line 1594) | func TestContextRenderRedirectWithAbsolutePath(t *testing.T) {
  function TestContextRenderRedirectWith201 (line 1606) | func TestContextRenderRedirectWith201(t *testing.T) {
  function TestContextRenderRedirectAll (line 1618) | func TestContextRenderRedirectAll(t *testing.T) {
  function TestContextNegotiationWithJSON (line 1629) | func TestContextNegotiationWithJSON(t *testing.T) {
  function TestContextNegotiationWithXML (line 1644) | func TestContextNegotiationWithXML(t *testing.T) {
  function TestContextNegotiationWithYAML (line 1659) | func TestContextNegotiationWithYAML(t *testing.T) {
  function TestContextNegotiationWithTOML (line 1674) | func TestContextNegotiationWithTOML(t *testing.T) {
  function TestContextNegotiationWithHTML (line 1689) | func TestContextNegotiationWithHTML(t *testing.T) {
  function TestContextNegotiationWithPROTOBUF (line 1707) | func TestContextNegotiationWithPROTOBUF(t *testing.T) {
  function TestContextNegotiationWithBSON (line 1733) | func TestContextNegotiationWithBSON(t *testing.T) {
  function TestContextNegotiationNotSupport (line 1750) | func TestContextNegotiationNotSupport(t *testing.T) {
  function TestContextNegotiationFormat (line 1764) | func TestContextNegotiationFormat(t *testing.T) {
  function TestContextNegotiationFormatWithAccept (line 1773) | func TestContextNegotiationFormatWithAccept(t *testing.T) {
  function TestContextNegotiationFormatWithWildcardAccept (line 1783) | func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) {
  function TestContextNegotiationFormatCustom (line 1807) | func TestContextNegotiationFormatCustom(t *testing.T) {
  function TestContextNegotiationFormat2 (line 1820) | func TestContextNegotiationFormat2(t *testing.T) {
  function TestContextIsAborted (line 1828) | func TestContextIsAborted(t *testing.T) {
  function TestContextAbortWithStatus (line 1844) | func TestContextAbortWithStatus(t *testing.T) {
  type testJSONAbortMsg (line 1857) | type testJSONAbortMsg struct
  function TestContextAbortWithStatusJSON (line 1862) | func TestContextAbortWithStatusJSON(t *testing.T) {
  function TestContextAbortWithStatusPureJSON (line 1888) | func TestContextAbortWithStatusPureJSON(t *testing.T) {
  function TestContextError (line 1914) | func TestContextError(t *testing.T) {
  function TestContextTypedError (line 1949) | func TestContextTypedError(t *testing.T) {
  function TestContextAbortWithError (line 1963) | func TestContextAbortWithError(t *testing.T) {
  function TestContextClientIP (line 1974) | func TestContextClientIP(t *testing.T) {
  function resetContextForClientIPTests (line 2115) | func resetContextForClientIPTests(c *Context) {
  function TestContextContentType (line 2127) | func TestContextContentType(t *testing.T) {
  function TestContextBindRequestTooLarge (line 2135) | func TestContextBindRequestTooLarge(t *testing.T) {
  function TestContextAutoBindJSON (line 2166) | func TestContextAutoBindJSON(t *testing.T) {
  function TestContextBindWithJSON (line 2181) | func TestContextBindWithJSON(t *testing.T) {
  function TestContextBindWithXML (line 2198) | func TestContextBindWithXML(t *testing.T) {
  function TestContextBindPlain (line 2219) | func TestContextBindPlain(t *testing.T) {
  function TestContextBindHeader (line 2243) | func TestContextBindHeader(t *testing.T) {
  function TestContextBindWithQuery (line 2265) | func TestContextBindWithQuery(t *testing.T) {
  function TestContextBindWithYAML (line 2281) | func TestContextBindWithYAML(t *testing.T) {
  function TestContextBindWithTOML (line 2298) | func TestContextBindWithTOML(t *testing.T) {
  function TestContextBadAutoBind (line 2315) | func TestContextBadAutoBind(t *testing.T) {
  function TestContextAutoShouldBindJSON (line 2336) | func TestContextAutoShouldBindJSON(t *testing.T) {
  function TestContextShouldBindWithJSON (line 2351) | func TestContextShouldBindWithJSON(t *testing.T) {
  function TestContextShouldBindWithXML (line 2368) | func TestContextShouldBindWithXML(t *testing.T) {
  function TestContextShouldBindPlain (line 2389) | func TestContextShouldBindPlain(t *testing.T) {
  function TestContextShouldBindHeader (line 2413) | func TestContextShouldBindHeader(t *testing.T) {
  function TestContextShouldBindWithQuery (line 2435) | func TestContextShouldBindWithQuery(t *testing.T) {
  function TestContextShouldBindWithYAML (line 2455) | func TestContextShouldBindWithYAML(t *testing.T) {
  function TestContextShouldBindWithTOML (line 2472) | func TestContextShouldBindWithTOML(t *testing.T) {
  function TestContextBadAutoShouldBind (line 2489) | func TestContextBadAutoShouldBind(t *testing.T) {
  function TestContextShouldBindBodyWith (line 2508) | func TestContextShouldBindBodyWith(t *testing.T) {
  function TestContextShouldBindBodyWithJSON (line 2587) | func TestContextShouldBindBodyWithJSON(t *testing.T) {
  function TestContextShouldBindBodyWithXML (line 2651) | func TestContextShouldBindBodyWithXML(t *testing.T) {
  function TestContextShouldBindBodyWithYAML (line 2715) | func TestContextShouldBindBodyWithYAML(t *testing.T) {
  function TestContextShouldBindBodyWithTOML (line 2780) | func TestContextShouldBindBodyWithTOML(t *testing.T) {
  function TestContextShouldBindBodyWithPlain (line 2844) | func TestContextShouldBindBodyWithPlain(t *testing.T) {
  function TestContextGolangContext (line 2919) | func TestContextGolangContext(t *testing.T) {
  function TestWebsocketsRequired (line 2936) | func TestWebsocketsRequired(t *testing.T) {
  function TestGetRequestHeaderValue (line 2958) | func TestGetRequestHeaderValue(t *testing.T) {
  function TestContextGetRawData (line 2967) | func TestContextGetRawData(t *testing.T) {
  function TestContextGetRawDataNilBody (line 2978) | func TestContextGetRawDataNilBody(t *testing.T) {
  function TestContextRenderDataFromReader (line 2988) | func TestContextRenderDataFromReader(t *testing.T) {
  function TestContextRenderDataFromReaderNoHeaders (line 3007) | func TestContextRenderDataFromReaderNoHeaders(t *testing.T) {
  type TestResponseRecorder (line 3024) | type TestResponseRecorder struct
    method CloseNotify (line 3029) | func (r *TestResponseRecorder) CloseNotify() <-chan bool {
    method closeClient (line 3033) | func (r *TestResponseRecorder) closeClient() {
  function CreateTestResponseRecorder (line 3037) | func CreateTestResponseRecorder() *TestResponseRecorder {
  function TestContextStream (line 3044) | func TestContextStream(t *testing.T) {
  function TestContextStreamWithClientGone (line 3063) | func TestContextStreamWithClientGone(t *testing.T) {
  function TestContextResetInHandler (line 3081) | func TestContextResetInHandler(t *testing.T) {
  function TestRaceParamsContextCopy (line 3093) | func TestRaceParamsContextCopy(t *testing.T) {
  function TestContextWithKeysMutex (line 3114) | func TestContextWithKeysMutex(t *testing.T) {
  function TestRemoteIPFail (line 3127) | func TestRemoteIPFail(t *testing.T) {
  function TestHasRequestContext (line 3137) | func TestHasRequestContext(t *testing.T) {
  function TestContextWithFallbackDeadlineFromRequestContext (line 3155) | func TestContextWithFallbackDeadlineFromRequestContext(t *testing.T) {
  function TestContextWithFallbackDoneFromRequestContext (line 3178) | func TestContextWithFallbackDoneFromRequestContext(t *testing.T) {
  function TestContextWithFallbackErrFromRequestContext (line 3196) | func TestContextWithFallbackErrFromRequestContext(t *testing.T) {
  function TestContextWithFallbackValueFromRequestContext (line 3215) | func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
  function TestContextCopyShouldNotCancel (line 3280) | func TestContextCopyShouldNotCancel(t *testing.T) {
  function TestContextAddParam (line 3344) | func TestContextAddParam(t *testing.T) {
  function TestCreateTestContextWithRouteParams (line 3355) | func TestCreateTestContextWithRouteParams(t *testing.T) {
  type interceptedWriter (line 3369) | type interceptedWriter struct
    method WriteHeader (line 3374) | func (i interceptedWriter) WriteHeader(code int) {
  function TestInterceptedHeader (line 3379) | func TestInterceptedHeader(t *testing.T) {
  function TestContextNext (line 3408) | func TestContextNext(t *testing.T) {
  function TestContextSetCookieData (line 3452) | func TestContextSetCookieData(t *testing.T) {
  function TestGetMapFromFormData (line 3596) | func TestGetMapFromFormData(t *testing.T) {
  function BenchmarkGetMapFromFormData (line 3727) | func BenchmarkGetMapFromFormData(b *testing.B) {

FILE: debug.go
  constant ginSupportMinGoVer (line 16) | ginSupportMinGoVer = 25
  function IsDebugging (line 22) | func IsDebugging() bool {
  function debugPrintRoute (line 32) | func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersC...
  function debugPrintLoadTemplate (line 44) | func debugPrintLoadTemplate(tmpl *template.Template) {
  function debugPrint (line 56) | func debugPrint(format string, values ...any) {
  function getMinVer (line 72) | func getMinVer(v string) (uint64, error) {
  function debugPrintWARNINGDefault (line 81) | func debugPrintWARNINGDefault() {
  function debugPrintWARNINGNew (line 92) | func debugPrintWARNINGNew() {
  function debugPrintWARNINGSetHTMLTemplate (line 100) | func debugPrintWARNINGSetHTMLTemplate() {
  function debugPrintError (line 110) | func debugPrintError(err error) {

FILE: debug_test.go
  function TestIsDebugging (line 23) | func TestIsDebugging(t *testing.T) {
  function TestDebugPrint (line 32) | func TestDebugPrint(t *testing.T) {
  function TestDebugPrintFunc (line 46) | func TestDebugPrintFunc(t *testing.T) {
  function TestDebugPrintError (line 58) | func TestDebugPrintError(t *testing.T) {
  function TestDebugPrintRoutes (line 68) | func TestDebugPrintRoutes(t *testing.T) {
  function TestDebugPrintRouteFunc (line 77) | func TestDebugPrintRouteFunc(t *testing.T) {
  function TestDebugPrintLoadTemplate (line 89) | func TestDebugPrintLoadTemplate(t *testing.T) {
  function TestDebugPrintWARNINGSetHTMLTemplate (line 99) | func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
  function TestDebugPrintWARNINGDefault (line 108) | func TestDebugPrintWARNINGDefault(t *testing.T) {
  function TestDebugPrintWARNINGDefaultWithUnsupportedVersion (line 117) | func TestDebugPrintWARNINGDefaultWithUnsupportedVersion(t *testing.T) {
  function TestDebugPrintWARNINGNew (line 127) | func TestDebugPrintWARNINGNew(t *testing.T) {
  function captureOutput (line 136) | func captureOutput(t *testing.T, f func()) string {
  function TestGetMinVer (line 167) | func TestGetMinVer(t *testing.T) {

FILE: deprecated.go
  method BindWith (line 17) | func (c *Context) BindWith(obj any, b binding.Binding) error {

FILE: deprecated_test.go
  function TestBindWith (line 17) | func TestBindWith(t *testing.T) {

FILE: errors.go
  type ErrorType (line 16) | type ErrorType
  constant ErrorTypeBind (line 20) | ErrorTypeBind ErrorType = 1 << 63
  constant ErrorTypeRender (line 22) | ErrorTypeRender ErrorType = 1 << 62
  constant ErrorTypePrivate (line 24) | ErrorTypePrivate ErrorType = 1 << 0
  constant ErrorTypePublic (line 26) | ErrorTypePublic ErrorType = 1 << 1
  constant ErrorTypeAny (line 28) | ErrorTypeAny ErrorType = 1<<64 - 1
  type Error (line 32) | type Error struct
    method SetType (line 43) | func (msg *Error) SetType(flags ErrorType) *Error {
    method SetMeta (line 49) | func (msg *Error) SetMeta(data any) *Error {
    method JSON (line 55) | func (msg *Error) JSON() any {
    method MarshalJSON (line 77) | func (msg *Error) MarshalJSON() ([]byte, error) {
    method Error (line 82) | func (msg Error) Error() string {
    method IsType (line 87) | func (msg *Error) IsType(flags ErrorType) bool {
    method Unwrap (line 92) | func (msg Error) Unwrap() error {
  type errorMsgs (line 38) | type errorMsgs
    method ByType (line 98) | func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
    method Last (line 116) | func (a errorMsgs) Last() *Error {
    method Errors (line 130) | func (a errorMsgs) Errors() []string {
    method JSON (line 141) | func (a errorMsgs) JSON() any {
    method MarshalJSON (line 157) | func (a errorMsgs) MarshalJSON() ([]byte, error) {
    method String (line 161) | func (a errorMsgs) String() string {

FILE: errors_test.go
  function TestError (line 17) | func TestError(t *testing.T) {
  function TestErrorSlice (line 68) | func TestErrorSlice(t *testing.T) {
  type TestErr (line 110) | type TestErr
    method Error (line 112) | func (e TestErr) Error() string { return string(e) }
  function TestErrorUnwrap (line 116) | func TestErrorUnwrap(t *testing.T) {

FILE: fs.go
  type OnlyFilesFS (line 13) | type OnlyFilesFS struct
    method Open (line 18) | func (o OnlyFilesFS) Open(name string) (http.File, error) {
  type neutralizedReaddirFile (line 28) | type neutralizedReaddirFile struct
    method Readdir (line 33) | func (n neutralizedReaddirFile) Readdir(_ int) ([]os.FileInfo, error) {
  function Dir (line 42) | func Dir(root string, listDirectory bool) http.FileSystem {

FILE: fs_test.go
  type mockFileSystem (line 13) | type mockFileSystem struct
    method Open (line 17) | func (m *mockFileSystem) Open(name string) (http.File, error) {
  function TestOnlyFilesFS_Open (line 21) | func TestOnlyFilesFS_Open(t *testing.T) {
  function TestOnlyFilesFS_Open_err (line 36) | func TestOnlyFilesFS_Open_err(t *testing.T) {
  function Test_neuteredReaddirFile_Readdir (line 51) | func Test_neuteredReaddirFile_Readdir(t *testing.T) {
  function TestDir_listDirectory (line 60) | func TestDir_listDirectory(t *testing.T) {
  function TestDir (line 67) | func TestDir(t *testing.T) {

FILE: gin.go
  constant defaultMultipartMemory (line 26) | defaultMultipartMemory = 32 << 20
  constant escapedColon (line 27) | escapedColon           = "\\:"
  constant colon (line 28) | colon                  = ":"
  constant backslash (line 29) | backslash              = "\\"
  type HandlerFunc (line 51) | type HandlerFunc
  type OptionFunc (line 54) | type OptionFunc
  type HandlersChain (line 57) | type HandlersChain
    method Last (line 60) | func (c HandlersChain) Last() HandlerFunc {
  type RouteInfo (line 68) | type RouteInfo struct
  type RoutesInfo (line 76) | type RoutesInfo
  constant PlatformGoogleAppEngine (line 82) | PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
  constant PlatformCloudflare (line 85) | PlatformCloudflare = "CF-Connecting-IP"
  constant PlatformFlyIO (line 87) | PlatformFlyIO = "Fly-Client-IP"
  type Engine (line 92) | type Engine struct
    method Handler (line 243) | func (engine *Engine) Handler() http.Handler {
    method allocateContext (line 252) | func (engine *Engine) allocateContext(maxParams uint16) *Context {
    method Delims (line 259) | func (engine *Engine) Delims(left, right string) *Engine {
    method SecureJsonPrefix (line 265) | func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
    method LoadHTMLGlob (line 272) | func (engine *Engine) LoadHTMLGlob(pattern string) {
    method LoadHTMLFiles (line 288) | func (engine *Engine) LoadHTMLFiles(files ...string) {
    method LoadHTMLFS (line 300) | func (engine *Engine) LoadHTMLFS(fs http.FileSystem, patterns ...strin...
    method SetHTMLTemplate (line 312) | func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
    method SetFuncMap (line 321) | func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
    method NoRoute (line 326) | func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
    method NoMethod (line 332) | func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
    method Use (line 340) | func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
    method With (line 348) | func (engine *Engine) With(opts ...OptionFunc) *Engine {
    method rebuild404Handlers (line 356) | func (engine *Engine) rebuild404Handlers() {
    method rebuild405Handlers (line 360) | func (engine *Engine) rebuild405Handlers() {
    method addRoute (line 364) | func (engine *Engine) addRoute(method, path string, handlers HandlersC...
    method Routes (line 390) | func (engine *Engine) Routes() (routes RoutesInfo) {
    method prepareTrustedCIDRs (line 414) | func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) {
    method SetTrustedProxies (line 451) | func (engine *Engine) SetTrustedProxies(trustedProxies []string) error {
    method isUnsafeTrustedProxies (line 457) | func (engine *Engine) isUnsafeTrustedProxies() bool {
    method parseTrustedProxies (line 462) | func (engine *Engine) parseTrustedProxies() error {
    method isTrustedProxy (line 469) | func (engine *Engine) isTrustedProxy(ip net.IP) bool {
    method validateHeader (line 482) | func (engine *Engine) validateHeader(header string) (clientIP string, ...
    method updateRouteTrees (line 517) | func (engine *Engine) updateRouteTrees() {
    method Run (line 540) | func (engine *Engine) Run(addr ...string) (err error) {
    method RunTLS (line 561) | func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err erro...
    method RunUnix (line 581) | func (engine *Engine) RunUnix(file string) (err error) {
    method RunFd (line 607) | func (engine *Engine) RunFd(fd int) (err error) {
    method RunQUIC (line 630) | func (engine *Engine) RunQUIC(addr, certFile, keyFile string) (err err...
    method RunListener (line 645) | func (engine *Engine) RunListener(listener net.Listener) (err error) {
    method ServeHTTP (line 662) | func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Reque...
    method HandleContext (line 680) | func (engine *Engine) HandleContext(c *Context) {
    method handleHTTPRequest (line 690) | func (engine *Engine) handleHTTPRequest(c *Context) {
  function New (line 202) | func New(opts ...OptionFunc) *Engine {
  function Default (line 236) | func Default(opts ...OptionFunc) *Engine {
  function iterate (line 397) | func iterate(path, method string, routes RoutesInfo, root *node) RoutesI...
  function updateRouteTree (line 504) | func updateRouteTree(n *node) {
  function parseIP (line 525) | func parseIP(ip string) net.IP {
  function serveError (line 764) | func serveError(c *Context, code int, defaultMessage []byte) {
  function redirectTrailingSlash (line 781) | func redirectTrailingSlash(c *Context) {
  function sanitizePathChars (line 799) | func sanitizePathChars(s string) string {
  function redirectFixedPath (line 808) | func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
  function redirectRequest (line 820) | func redirectRequest(c *Context) {

FILE: ginS/gins.go
  function LoadHTMLGlob (line 20) | func LoadHTMLGlob(pattern string) {
  function LoadHTMLFiles (line 25) | func LoadHTMLFiles(files ...string) {
  function LoadHTMLFS (line 30) | func LoadHTMLFS(fs http.FileSystem, patterns ...string) {
  function SetHTMLTemplate (line 35) | func SetHTMLTemplate(templ *template.Template) {
  function NoRoute (line 40) | func NoRoute(handlers ...gin.HandlerFunc) {
  function NoMethod (line 45) | func NoMethod(handlers ...gin.HandlerFunc) {
  function Group (line 51) | func Group(relativePath string, handlers ...gin.HandlerFunc) *gin.Router...
  function Handle (line 56) | func Handle(httpMethod, relativePath string, handlers ...gin.HandlerFunc...
  function POST (line 61) | func POST(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function GET (line 66) | func GET(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function DELETE (line 71) | func DELETE(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function PATCH (line 76) | func PATCH(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function PUT (line 81) | func PUT(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function OPTIONS (line 86) | func OPTIONS(relativePath string, handlers ...gin.HandlerFunc) gin.IRout...
  function HEAD (line 91) | func HEAD(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function Any (line 96) | func Any(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function StaticFile (line 101) | func StaticFile(relativePath, filepath string) gin.IRoutes {
  function Static (line 112) | func Static(relativePath, root string) gin.IRoutes {
  function StaticFS (line 117) | func StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes {
  function Use (line 124) | func Use(middlewares ...gin.HandlerFunc) gin.IRoutes {
  function Routes (line 129) | func Routes() gin.RoutesInfo {
  function Run (line 136) | func Run(addr ...string) (err error) {
  function RunTLS (line 143) | func RunTLS(addr, certFile, keyFile string) (err error) {
  function RunUnix (line 150) | func RunUnix(file string) (err error) {
  function RunFd (line 157) | func RunFd(fd int) (err error) {

FILE: ginS/gins_test.go
  function init (line 17) | func init() {
  function TestGET (line 21) | func TestGET(t *testing.T) {
  function TestPOST (line 34) | func TestPOST(t *testing.T) {
  function TestPUT (line 47) | func TestPUT(t *testing.T) {
  function TestDELETE (line 60) | func TestDELETE(t *testing.T) {
  function TestPATCH (line 73) | func TestPATCH(t *testing.T) {
  function TestOPTIONS (line 86) | func TestOPTIONS(t *testing.T) {
  function TestHEAD (line 99) | func TestHEAD(t *testing.T) {
  function TestAny (line 111) | func TestAny(t *testing.T) {
  function TestHandle (line 124) | func TestHandle(t *testing.T) {
  function TestGroup (line 137) | func TestGroup(t *testing.T) {
  function TestUse (line 151) | func TestUse(t *testing.T) {
  function TestNoRoute (line 170) | func TestNoRoute(t *testing.T) {
  function TestNoMethod (line 183) | func TestNoMethod(t *testing.T) {
  function TestRoutes (line 193) | func TestRoutes(t *testing.T) {
  function TestSetHTMLTemplate (line 209) | func TestSetHTMLTemplate(t *testing.T) {
  function TestStaticFile (line 217) | func TestStaticFile(t *testing.T) {
  function TestStatic (line 227) | func TestStatic(t *testing.T) {
  function TestStaticFS (line 237) | func TestStaticFS(t *testing.T) {

FILE: gin_integration_test.go
  function testRequest (line 31) | func testRequest(t *testing.T, params ...string) {
  function TestRunEmpty (line 66) | func TestRunEmpty(t *testing.T) {
  function TestBadTrustedCIDRs (line 82) | func TestBadTrustedCIDRs(t *testing.T) {
  function TestRunTLS (line 157) | func TestRunTLS(t *testing.T) {
  function TestPusher (line 173) | func TestPusher(t *testing.T) {
  function TestRunEmptyWithEnv (line 210) | func TestRunEmptyWithEnv(t *testing.T) {
  function TestRunTooMuchParams (line 226) | func TestRunTooMuchParams(t *testing.T) {
  function TestRunWithPort (line 233) | func TestRunWithPort(t *testing.T) {
  function TestUnixSocket (line 248) | func TestUnixSocket(t *testing.T) {
  function TestBadUnixSocket (line 277) | func TestBadUnixSocket(t *testing.T) {
  function TestRunQUIC (line 282) | func TestRunQUIC(t *testing.T) {
  function TestFileDescriptor (line 298) | func TestFileDescriptor(t *testing.T) {
  function TestBadFileDescriptor (line 339) | func TestBadFileDescriptor(t *testing.T) {
  function TestListener (line 344) | func TestListener(t *testing.T) {
  function TestBadListener (line 372) | func TestBadListener(t *testing.T) {
  function TestWithHttptestWithAutoSelectedPort (line 382) | func TestWithHttptestWithAutoSelectedPort(t *testing.T) {
  function TestConcurrentHandleContext (line 392) | func TestConcurrentHandleContext(t *testing.T) {
  function TestTreeRunDynamicRouting (line 434) | func TestTreeRunDynamicRouting(t *testing.T) {
  function isWindows (line 580) | func isWindows() bool {
  function TestEscapedColon (line 584) | func TestEscapedColon(t *testing.T) {

FILE: gin_test.go
  function formatAsDate (line 27) | func formatAsDate(t time.Time) string {
  function setupHTMLFiles (line 32) | func setupHTMLFiles(t *testing.T, mode string, tls bool, loadMethod func...
  function TestLoadHTMLGlobDebugMode (line 65) | func TestLoadHTMLGlobDebugMode(t *testing.T) {
  function TestH2c (line 85) | func TestH2c(t *testing.T) {
  function TestLoadHTMLGlobTestMode (line 123) | func TestLoadHTMLGlobTestMode(t *testing.T) {
  function TestLoadHTMLGlobReleaseMode (line 143) | func TestLoadHTMLGlobReleaseMode(t *testing.T) {
  function TestLoadHTMLGlobUsingTLS (line 163) | func TestLoadHTMLGlobUsingTLS(t *testing.T) {
  function TestLoadHTMLGlobFromFuncMap (line 190) | func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
  function init (line 210) | func init() {
  function TestCreateEngine (line 214) | func TestCreateEngine(t *testing.T) {
  function TestLoadHTMLFilesTestMode (line 221) | func TestLoadHTMLFilesTestMode(t *testing.T) {
  function TestLoadHTMLFilesDebugMode (line 241) | func TestLoadHTMLFilesDebugMode(t *testing.T) {
  function TestLoadHTMLFilesReleaseMode (line 261) | func TestLoadHTMLFilesReleaseMode(t *testing.T) {
  function TestLoadHTMLFilesUsingTLS (line 281) | func TestLoadHTMLFilesUsingTLS(t *testing.T) {
  function TestLoadHTMLFilesFuncMap (line 308) | func TestLoadHTMLFilesFuncMap(t *testing.T) {
  function TestLoadHTMLFSTestMode (line 330) | func TestLoadHTMLFSTestMode(t *testing.T) {
  function TestLoadHTMLFSDebugMode (line 350) | func TestLoadHTMLFSDebugMode(t *testing.T) {
  function TestLoadHTMLFSReleaseMode (line 370) | func TestLoadHTMLFSReleaseMode(t *testing.T) {
  function TestLoadHTMLFSUsingTLS (line 390) | func TestLoadHTMLFSUsingTLS(t *testing.T) {
  function TestLoadHTMLFSFuncMap (line 417) | func TestLoadHTMLFSFuncMap(t *testing.T) {
  function TestAddRoute (line 437) | func TestAddRoute(t *testing.T) {
  function TestAddRouteFails (line 455) | func TestAddRouteFails(t *testing.T) {
  function TestCreateDefaultRouter (line 467) | func TestCreateDefaultRouter(t *testing.T) {
  function TestNoRouteWithoutGlobalHandlers (line 472) | func TestNoRouteWithoutGlobalHandlers(t *testing.T) {
  function TestNoRouteWithGlobalHandlers (line 494) | func TestNoRouteWithGlobalHandlers(t *testing.T) {
  function TestNoMethodWithoutGlobalHandlers (line 525) | func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
  function TestRebuild404Handlers (line 547) | func TestRebuild404Handlers(t *testing.T) {
  function TestNoMethodWithGlobalHandlers (line 573) | func TestNoMethodWithGlobalHandlers(t *testing.T) {
  function compareFunc (line 604) | func compareFunc(t *testing.T, a, b any) {
  function TestListOfRoutes (line 612) | func TestListOfRoutes(t *testing.T) {
  function TestEngineHandleContext (line 654) | func TestEngineHandleContext(t *testing.T) {
  function TestEngineHandleContextManyReEntries (line 671) | func TestEngineHandleContextManyReEntries(t *testing.T) {
  function TestEngineHandleContextPreventsMiddlewareReEntry (line 708) | func TestEngineHandleContextPreventsMiddlewareReEntry(t *testing.T) {
  function TestEngineHandleContextNoRouteWithGroupMiddleware (line 746) | func TestEngineHandleContextNoRouteWithGroupMiddleware(t *testing.T) {
  function TestEngineHandleContextNoRouteWithEngineMiddleware (line 781) | func TestEngineHandleContextNoRouteWithEngineMiddleware(t *testing.T) {
  function TestEngineHandleContextUseEscapedPathPercentEncoded (line 818) | func TestEngineHandleContextUseEscapedPathPercentEncoded(t *testing.T) {
  function TestEngineHandleContextUseRawPathPercentEncoded (line 834) | func TestEngineHandleContextUseRawPathPercentEncoded(t *testing.T) {
  function TestEngineHandleContextUseEscapedPathOverride (line 850) | func TestEngineHandleContextUseEscapedPathOverride(t *testing.T) {
  function TestPrepareTrustedCIRDsWith (line 867) | func TestPrepareTrustedCIRDsWith(t *testing.T) {
  function parseCIDR (line 972) | func parseCIDR(cidr string) *net.IPNet {
  function assertRoutePresent (line 980) | func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute Ro...
  function handlerTest1 (line 990) | func handlerTest1(c *Context) {}
  function handlerTest2 (line 991) | func handlerTest2(c *Context) {}
  function TestNewOptionFunc (line 993) | func TestNewOptionFunc(t *testing.T) {
  function TestWithOptionFunc (line 1010) | func TestWithOptionFunc(t *testing.T) {
  type Birthday (line 1027) | type Birthday
    method UnmarshalParam (line 1029) | func (b *Birthday) UnmarshalParam(param string) error {
  function TestCustomUnmarshalStruct (line 1034) | func TestCustomUnmarshalStruct(t *testing.T) {
  function TestMethodNotAllowedNoRoute (line 1051) | func TestMethodNotAllowedNoRoute(t *testing.T) {
  function TestLiteralColonWithRun (line 1062) | func TestLiteralColonWithRun(t *testing.T) {
  function TestLiteralColonWithDirectServeHTTP (line 1081) | func TestLiteralColonWithDirectServeHTTP(t *testing.T) {
  function TestLiteralColonWithHandler (line 1097) | func TestLiteralColonWithHandler(t *testing.T) {
  function TestLiteralColonWithHTTPServer (line 1115) | func TestLiteralColonWithHTTPServer(t *testing.T) {
  function TestUpdateRouteTreesCalledOnce (line 1143) | func TestUpdateRouteTreesCalledOnce(t *testing.T) {

FILE: githubapi_test.go
  type route (line 21) | type route struct
  function TestShouldBindUri (line 290) | func TestShouldBindUri(t *testing.T) {
  function TestBindUri (line 312) | func TestBindUri(t *testing.T) {
  function TestBindUriError (line 334) | func TestBindUriError(t *testing.T) {
  function TestRaceContextCopy (line 351) | func TestRaceContextCopy(t *testing.T) {
  function readWriteKeys (line 367) | func readWriteKeys(c *Context) {
  function githubConfigRouter (line 374) | func githubConfigRouter(router *Engine) {
  function TestGithubAPI (line 387) | func TestGithubAPI(t *testing.T) {
  function exampleFromPath (line 405) | func exampleFromPath(path string) (string, Params) {
  function BenchmarkGithub (line 440) | func BenchmarkGithub(b *testing.B) {
  function BenchmarkParallelGithub (line 446) | func BenchmarkParallelGithub(b *testing.B) {
  function BenchmarkParallelGithubDefault (line 462) | func BenchmarkParallelGithubDefault(b *testing.B) {

FILE: internal/bytesconv/bytesconv.go
  function StringToBytes (line 13) | func StringToBytes(s string) []byte {
  function BytesToString (line 19) | func BytesToString(b []byte) string {

FILE: internal/bytesconv/bytesconv_test.go
  function rawBytesToStr (line 21) | func rawBytesToStr(b []byte) string {
  function rawStrToBytes (line 25) | func rawStrToBytes(s string) []byte {
  function TestBytesToString (line 31) | func TestBytesToString(t *testing.T) {
  function TestBytesToStringEmpty (line 44) | func TestBytesToStringEmpty(t *testing.T) {
  constant letterBytes (line 53) | letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  constant letterIdxBits (line 55) | letterIdxBits = 6
  constant letterIdxMask (line 56) | letterIdxMask = 1<<letterIdxBits - 1
  constant letterIdxMax (line 57) | letterIdxMax  = 63 / letterIdxBits
  function RandStringBytesMaskImprSrcSB (line 62) | func RandStringBytesMaskImprSrcSB(n int) string {
  function TestStringToBytes (line 81) | func TestStringToBytes(t *testing.T) {
  function TestStringToBytesEmpty (line 90) | func TestStringToBytesEmpty(t *testing.T) {
  function BenchmarkBytesConvBytesToStrRaw (line 102) | func BenchmarkBytesConvBytesToStrRaw(b *testing.B) {
  function BenchmarkBytesConvBytesToStr (line 108) | func BenchmarkBytesConvBytesToStr(b *testing.B) {
  function BenchmarkBytesConvStrToBytesRaw (line 114) | func BenchmarkBytesConvStrToBytesRaw(b *testing.B) {
  function BenchmarkBytesConvStrToBytes (line 120) | func BenchmarkBytesConvStrToBytes(b *testing.B) {

FILE: internal/fs/fs.go
  type FileSystem (line 9) | type FileSystem struct
    method Open (line 14) | func (o FileSystem) Open(name string) (fs.File, error) {

FILE: internal/fs/fs_test.go
  type mockFileSystem (line 13) | type mockFileSystem struct
    method Open (line 17) | func (m *mockFileSystem) Open(name string) (http.File, error) {
  function TestFileSystem_Open (line 21) | func TestFileSystem_Open(t *testing.T) {
  function TestFileSystem_Open_err (line 36) | func TestFileSystem_Open_err(t *testing.T) {

FILE: logger.go
  type consoleColorModeValue (line 17) | type consoleColorModeValue
  constant autoColor (line 20) | autoColor consoleColorModeValue = iota
  constant disableColor (line 21) | disableColor
  constant forceColor (line 22) | forceColor
  constant green (line 26) | green   = "\033[97;42m"
  constant white (line 27) | white   = "\033[90;47m"
  constant yellow (line 28) | yellow  = "\033[90;43m"
  constant red (line 29) | red     = "\033[97;41m"
  constant blue (line 30) | blue    = "\033[97;44m"
  constant magenta (line 31) | magenta = "\033[97;45m"
  constant cyan (line 32) | cyan    = "\033[97;46m"
  constant reset (line 33) | reset   = "\033[0m"
  type LoggerConfig (line 39) | type LoggerConfig struct
  type Skipper (line 62) | type Skipper
  type LogFormatter (line 65) | type LogFormatter
  type LogFormatterParams (line 68) | type LogFormatterParams struct
    method StatusCodeColor (line 94) | func (p *LogFormatterParams) StatusCodeColor() string {
    method LatencyColor (line 112) | func (p *LogFormatterParams) LatencyColor() string {
    method MethodColor (line 133) | func (p *LogFormatterParams) MethodColor() string {
    method ResetColor (line 157) | func (p *LogFormatterParams) ResetColor() string {
    method IsOutputColor (line 162) | func (p *LogFormatterParams) IsOutputColor() bool {
  function DisableConsoleColor (line 197) | func DisableConsoleColor() {
  function ForceConsoleColor (line 202) | func ForceConsoleColor() {
  function ErrorLogger (line 207) | func ErrorLogger() HandlerFunc {
  function ErrorLoggerT (line 212) | func ErrorLoggerT(typ ErrorType) HandlerFunc {
  function Logger (line 224) | func Logger() HandlerFunc {
  function LoggerWithFormatter (line 229) | func LoggerWithFormatter(f LogFormatter) HandlerFunc {
  function LoggerWithWriter (line 237) | func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
  function LoggerWithConfig (line 245) | func LoggerWithConfig(conf LoggerConfig) HandlerFunc {

FILE: logger_test.go
  function init (line 18) | func init() {
  function TestLogger (line 22) | func TestLogger(t *testing.T) {
  function TestLoggerWithConfig (line 86) | func TestLoggerWithConfig(t *testing.T) {
  function TestLoggerWithFormatter (line 150) | func TestLoggerWithFormatter(t *testing.T) {
  function TestLoggerWithConfigFormatting (line 182) | func TestLoggerWithConfigFormatting(t *testing.T) {
  function TestDefaultLogFormatter (line 234) | func TestDefaultLogFormatter(t *testing.T) {
  function TestColorForMethod (line 287) | func TestColorForMethod(t *testing.T) {
  function TestColorForStatus (line 305) | func TestColorForStatus(t *testing.T) {
  function TestColorForLatency (line 320) | func TestColorForLatency(t *testing.T) {
  function TestResetColor (line 338) | func TestResetColor(t *testing.T) {
  function TestIsOutputColor (line 343) | func TestIsOutputColor(t *testing.T) {
  function TestErrorLogger (line 376) | func TestErrorLogger(t *testing.T) {
  function TestLoggerWithWriterSkippingPaths (line 403) | func TestLoggerWithWriterSkippingPaths(t *testing.T) {
  function TestLoggerWithConfigSkippingPaths (line 418) | func TestLoggerWithConfigSkippingPaths(t *testing.T) {
  function TestLoggerWithConfigSkipper (line 436) | func TestLoggerWithConfigSkipper(t *testing.T) {
  function TestDisableConsoleColor (line 456) | func TestDisableConsoleColor(t *testing.T) {
  function TestForceConsoleColor (line 466) | func TestForceConsoleColor(t *testing.T) {
  function TestLoggerWithConfigSkipQueryString (line 476) | func TestLoggerWithConfigSkipQueryString(t *testing.T) {

FILE: middleware_test.go
  function TestMiddlewareGeneralCase (line 17) | func TestMiddlewareGeneralCase(t *testing.T) {
  function TestMiddlewareNoRoute (line 45) | func TestMiddlewareNoRoute(t *testing.T) {
  function TestMiddlewareNoMethodEnabled (line 81) | func TestMiddlewareNoMethodEnabled(t *testing.T) {
  function TestMiddlewareNoMethodDisabled (line 118) | func TestMiddlewareNoMethodDisabled(t *testing.T) {
  function TestMiddlewareAbort (line 159) | func TestMiddlewareAbort(t *testing.T) {
  function TestMiddlewareAbortHandlersChainAndNext (line 185) | func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) {
  function TestMiddlewareFailHandlersChain (line 208) | func TestMiddlewareFailHandlersChain(t *testing.T) {
  function TestMiddlewareWrite (line 229) | func TestMiddlewareWrite(t *testing.T) {

FILE: mode.go
  constant EnvGinMode (line 17) | EnvGinMode = "GIN_MODE"
  constant DebugMode (line 21) | DebugMode = "debug"
  constant ReleaseMode (line 23) | ReleaseMode = "release"
  constant TestMode (line 25) | TestMode = "test"
  constant debugCode (line 29) | debugCode = iota
  constant releaseCode (line 30) | releaseCode
  constant testCode (line 31) | testCode
  function init (line 52) | func init() {
  function SetMode (line 58) | func SetMode(value string) {
  function DisableBindValidation (line 81) | func DisableBindValidation() {
  function EnableJsonDecoderUseNumber (line 87) | func EnableJsonDecoderUseNumber() {
  function EnableJsonDecoderDisallowUnknownFields (line 93) | func EnableJsonDecoderDisallowUnknownFields() {
  function Mode (line 98) | func Mode() string {

FILE: mode_test.go
  function init (line 16) | func init() {
  function TestSetMode (line 20) | func TestSetMode(t *testing.T) {
  function TestDisableBindValidation (line 44) | func TestDisableBindValidation(t *testing.T) {
  function TestEnableJsonDecoderUseNumber (line 52) | func TestEnableJsonDecoderUseNumber(t *testing.T) {
  function TestEnableJsonDecoderDisallowUnknownFields (line 58) | func TestEnableJsonDecoderDisallowUnknownFields(t *testing.T) {

FILE: path.go
  constant stackBufSize (line 8) | stackBufSize = 128
  function cleanPath (line 23) | func cleanPath(p string) string {
  function bufApp (line 128) | func bufApp(buf *[]byte, s string, w int, c byte) {
  function removeRepeatedChar (line 155) | func removeRepeatedChar(s string, char byte) string {

FILE: path_test.go
  type cleanPathTest (line 16) | type cleanPathTest struct
  function TestPathClean (line 72) | func TestPathClean(t *testing.T) {
  function TestPathCleanMallocs (line 79) | func TestPathCleanMallocs(t *testing.T) {
  function BenchmarkPathClean (line 94) | func BenchmarkPathClean(b *testing.B) {
  function genLongPaths (line 104) | func genLongPaths() (testPaths []cleanPathTest) {
  function TestPathCleanLong (line 126) | func TestPathCleanLong(t *testing.T) {
  function BenchmarkPathCleanLong (line 135) | func BenchmarkPathCleanLong(b *testing.B) {
  function TestRemoveRepeatedChar (line 147) | func TestRemoveRepeatedChar(t *testing.T) {

FILE: recovery.go
  constant dunno (line 27) | dunno     = "???"
  constant stackSkip (line 28) | stackSkip = 3
  type RecoveryFunc (line 32) | type RecoveryFunc
  function Recovery (line 35) | func Recovery() HandlerFunc {
  function CustomRecovery (line 40) | func CustomRecovery(handle RecoveryFunc) HandlerFunc {
  function RecoveryWithWriter (line 45) | func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) Handler...
  function CustomRecoveryWithWriter (line 53) | func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) Handle...
  function secureRequestDump (line 98) | func secureRequestDump(r *http.Request) string {
  function defaultHandleRecovery (line 109) | func defaultHandleRecovery(c *Context, _ any) {
  function stack (line 114) | func stack(skip int) []byte {
  function readNthLine (line 146) | func readNthLine(file string, n int) (string, error) {
  function function (line 172) | func function(pc uintptr) string {
  function timeFormat (line 197) | func timeFormat(t time.Time) string {

FILE: recovery_test.go
  function TestPanicClean (line 18) | func TestPanicClean(t *testing.T) {
  function TestPanicInHandler (line 50) | func TestPanicInHandler(t *testing.T) {
  function TestPanicWithAbort (line 78) | func TestPanicWithAbort(t *testing.T) {
  function TestFunction (line 91) | func TestFunction(t *testing.T) {
  function TestPanicWithBrokenPipe (line 98) | func TestPanicWithBrokenPipe(t *testing.T) {
  function TestPanicWithAbortHandler (line 132) | func TestPanicWithAbortHandler(t *testing.T) {
  function TestCustomRecoveryWithWriter (line 155) | func TestCustomRecoveryWithWriter(t *testing.T) {
  function TestCustomRecovery (line 189) | func TestCustomRecovery(t *testing.T) {
  function TestRecoveryWithWriterWithCustomRecovery (line 224) | func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) {
  function TestSecureRequestDump (line 259) | func TestSecureRequestDump(t *testing.T) {
  function TestReadNthLine (line 322) | func TestReadNthLine(t *testing.T) {
  function BenchmarkStack (line 364) | func BenchmarkStack(b *testing.B) {

FILE: render/bson.go
  type BSON (line 14) | type BSON struct
    method Render (line 21) | func (r BSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 32) | func (r BSON) WriteContentType(w http.ResponseWriter) {

FILE: render/data.go
  type Data (line 13) | type Data struct
    method Render (line 19) | func (r Data) Render(w http.ResponseWriter) (err error) {
    method WriteContentType (line 29) | func (r Data) WriteContentType(w http.ResponseWriter) {

FILE: render/html.go
  type Delims (line 15) | type Delims struct
  type HTMLRender (line 23) | type HTMLRender interface
  type HTMLProduction (line 29) | type HTMLProduction struct
    method Instance (line 54) | func (r HTMLProduction) Instance(name string, data any) Render {
  type HTMLDebug (line 35) | type HTMLDebug struct
    method Instance (line 63) | func (r HTMLDebug) Instance(name string, data any) Render {
    method loadTemplate (line 71) | func (r HTMLDebug) loadTemplate() *template.Template {
  type HTML (line 45) | type HTML struct
    method Render (line 89) | func (r HTML) Render(w http.ResponseWriter) error {
    method WriteContentType (line 99) | func (r HTML) WriteContentType(w http.ResponseWriter) {

FILE: render/json.go
  type JSON (line 19) | type JSON struct
    method Render (line 57) | func (r JSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 62) | func (r JSON) WriteContentType(w http.ResponseWriter) {
  type IndentedJSON (line 24) | type IndentedJSON struct
    method Render (line 78) | func (r IndentedJSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 89) | func (r IndentedJSON) WriteContentType(w http.ResponseWriter) {
  type SecureJSON (line 29) | type SecureJSON struct
    method Render (line 94) | func (r SecureJSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 112) | func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
  type JsonpJSON (line 35) | type JsonpJSON struct
    method Render (line 117) | func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
    method WriteContentType (line 150) | func (r JsonpJSON) WriteContentType(w http.ResponseWriter) {
  type AsciiJSON (line 41) | type AsciiJSON struct
    method Render (line 155) | func (r AsciiJSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 179) | func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
  type PureJSON (line 46) | type PureJSON struct
    method Render (line 184) | func (r PureJSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 192) | func (r PureJSON) WriteContentType(w http.ResponseWriter) {
  function WriteJSON (line 67) | func WriteJSON(w http.ResponseWriter, obj any) error {

FILE: render/msgpack.go
  type MsgPack (line 22) | type MsgPack struct
    method WriteContentType (line 29) | func (r MsgPack) WriteContentType(w http.ResponseWriter) {
    method Render (line 34) | func (r MsgPack) Render(w http.ResponseWriter) error {
  function WriteMsgPack (line 39) | func WriteMsgPack(w http.ResponseWriter, obj any) error {

FILE: render/pdf.go
  type PDF (line 10) | type PDF struct
    method Render (line 17) | func (r PDF) Render(w http.ResponseWriter) error {
    method WriteContentType (line 24) | func (r PDF) WriteContentType(w http.ResponseWriter) {

FILE: render/protobuf.go
  type ProtoBuf (line 14) | type ProtoBuf struct
    method Render (line 21) | func (r ProtoBuf) Render(w http.ResponseWriter) error {
    method WriteContentType (line 34) | func (r ProtoBuf) WriteContentType(w http.ResponseWriter) {

FILE: render/reader.go
  type Reader (line 14) | type Reader struct
    method Render (line 22) | func (r Reader) Render(w http.ResponseWriter) (err error) {
    method WriteContentType (line 36) | func (r Reader) WriteContentType(w http.ResponseWriter) {
    method writeHeaders (line 41) | func (r Reader) writeHeaders(w http.ResponseWriter) {

FILE: render/reader_test.go
  function TestReaderRenderNoHeaders (line 15) | func TestReaderRenderNoHeaders(t *testing.T) {

FILE: render/redirect.go
  type Redirect (line 13) | type Redirect struct
    method Render (line 20) | func (r Redirect) Render(w http.ResponseWriter) error {
    method WriteContentType (line 29) | func (r Redirect) WriteContentType(http.ResponseWriter) {}

FILE: render/render.go
  type Render (line 10) | type Render interface
  function writeContentType (line 37) | func writeContentType(w http.ResponseWriter, value []string) {

FILE: render/render_msgpack_test.go
  function TestRenderMsgPack (line 19) | func TestRenderMsgPack(t *testing.T) {
  function TestWriteMsgPack (line 41) | func TestWriteMsgPack(t *testing.T) {
  type failWriter (line 63) | type failWriter struct
    method Write (line 67) | func (w *failWriter) Write(data []byte) (int, error) {
  function TestRenderMsgPackError (line 71) | func TestRenderMsgPackError(t *testing.T) {

FILE: render/render_test.go
  function TestRenderJSON (line 26) | func TestRenderJSON(t *testing.T) {
  function TestRenderJSONError (line 43) | func TestRenderJSONError(t *testing.T) {
  function TestRenderIndentedJSON (line 51) | func TestRenderIndentedJSON(t *testing.T) {
  function TestRenderIndentedJSONPanics (line 65) | func TestRenderIndentedJSONPanics(t *testing.T) {
  function TestRenderSecureJSON (line 74) | func TestRenderSecureJSON(t *testing.T) {
  function TestRenderSecureJSONFail (line 102) | func TestRenderSecureJSONFail(t *testing.T) {
  function TestRenderJsonpJSON (line 111) | func TestRenderJsonpJSON(t *testing.T) {
  type errorWriter (line 139) | type errorWriter struct
    method Header (line 148) | func (w *errorWriter) Header() http.Header {
    method WriteHeader (line 155) | func (w *errorWriter) WriteHeader(statusCode int) {
    method Write (line 162) | func (w *errorWriter) Write(buf []byte) (int, error) {
    method reset (line 173) | func (w *errorWriter) reset() {
  function TestRenderJsonpJSONError (line 178) | func TestRenderJsonpJSONError(t *testing.T) {
  function TestRenderJsonpJSONError2 (line 219) | func TestRenderJsonpJSONError2(t *testing.T) {
  function TestRenderJsonpJSONFail (line 234) | func TestRenderJsonpJSONFail(t *testing.T) {
  function TestRenderAsciiJSON (line 243) | func TestRenderAsciiJSON(t *testing.T) {
  function TestRenderAsciiJSONFail (line 264) | func TestRenderAsciiJSONFail(t *testing.T) {
  function TestRenderPureJSON (line 272) | func TestRenderPureJSON(t *testing.T) {
  type xmlmap (line 284) | type xmlmap
    method MarshalXML (line 287) | func (h xmlmap) MarshalXML(e *xml.Encoder, start xml.StartElement) err...
  function TestRenderYAML (line 308) | func TestRenderYAML(t *testing.T) {
  type fail (line 332) | type fail struct
    method MarshalYAML (line 335) | func (ft *fail) MarshalYAML() (any, error) {
  function TestRenderYAMLFail (line 339) | func TestRenderYAMLFail(t *testing.T) {
  function TestRenderTOML (line 345) | func TestRenderTOML(t *testing.T) {
  function TestRenderTOMLFail (line 360) | func TestRenderTOMLFail(t *testing.T) {
  function TestRenderProtoBuf (line 367) | func TestRenderProtoBuf(t *testing.T) {
  function TestRenderProtoBufFail (line 388) | func TestRenderProtoBufFail(t *testing.T) {
  function TestRenderBSON (line 395) | func TestRenderBSON(t *testing.T) {
  function TestRenderBSONError (line 420) | func TestRenderBSONError(t *testing.T) {
  function TestRenderBSONWriteError (line 428) | func TestRenderBSONWriteError(t *testing.T) {
  function TestRenderXML (line 444) | func TestRenderXML(t *testing.T) {
  function TestRenderXMLError (line 460) | func TestRenderXMLError(t *testing.T) {
  function TestRenderPDF (line 469) | func TestRenderPDF(t *testing.T) {
  function TestRenderRedirect (line 485) | func TestRenderRedirect(t *testing.T) {
  function TestRenderData (line 525) | func TestRenderData(t *testing.T) {
  function TestRenderDataContentLength (line 540) | func TestRenderDataContentLength(t *testing.T) {
  function TestRenderDataError (line 569) | func TestRenderDataError(t *testing.T) {
  function TestRenderString (line 585) | func TestRenderString(t *testing.T) {
  function TestRenderStringLenZero (line 604) | func TestRenderStringLenZero(t *testing.T) {
  function TestRenderHTMLTemplate (line 617) | func TestRenderHTMLTemplate(t *testing.T) {
  function TestRenderHTMLTemplateEmptyName (line 633) | func TestRenderHTMLTemplateEmptyName(t *testing.T) {
  function TestRenderHTMLDebugFiles (line 649) | func TestRenderHTMLDebugFiles(t *testing.T) {
  function TestRenderHTMLDebugGlob (line 670) | func TestRenderHTMLDebugGlob(t *testing.T) {
  function TestRenderHTMLDebugFS (line 691) | func TestRenderHTMLDebugFS(t *testing.T) {
  function TestRenderHTMLDebugPanics (line 712) | func TestRenderHTMLDebugPanics(t *testing.T) {
  function TestRenderHTMLTemplateError (line 724) | func TestRenderHTMLTemplateError(t *testing.T) {
  function TestRenderHTMLTemplateExecuteError (line 737) | func TestRenderHTMLTemplateExecuteError(t *testing.T) {
  function TestRenderReader (line 750) | func TestRenderReader(t *testing.T) {
  function TestRenderReaderNoContentLength (line 773) | func TestRenderReaderNoContentLength(t *testing.T) {
  function TestRenderWriteError (line 796) | func TestRenderWriteError(t *testing.T) {

FILE: render/text.go
  type String (line 15) | type String struct
    method Render (line 23) | func (r String) Render(w http.ResponseWriter) error {
    method WriteContentType (line 28) | func (r String) WriteContentType(w http.ResponseWriter) {
  function WriteString (line 33) | func WriteString(w http.ResponseWriter, format string, data []any) (err ...

FILE: render/toml.go
  type TOML (line 14) | type TOML struct
    method Render (line 21) | func (r TOML) Render(w http.ResponseWriter) error {
    method WriteContentType (line 34) | func (r TOML) WriteContentType(w http.ResponseWriter) {

FILE: render/xml.go
  type XML (line 13) | type XML struct
    method Render (line 20) | func (r XML) Render(w http.ResponseWriter) error {
    method WriteContentType (line 26) | func (r XML) WriteContentType(w http.ResponseWriter) {

FILE: render/yaml.go
  type YAML (line 14) | type YAML struct
    method Render (line 21) | func (r YAML) Render(w http.ResponseWriter) error {
    method WriteContentType (line 34) | func (r YAML) WriteContentType(w http.ResponseWriter) {

FILE: response_writer.go
  constant noWritten (line 16) | noWritten     = -1
  constant defaultStatus (line 17) | defaultStatus = http.StatusOK
  type ResponseWriter (line 23) | type ResponseWriter interface
  type responseWriter (line 49) | type responseWriter struct
    method Unwrap (line 57) | func (w *responseWriter) Unwrap() http.ResponseWriter {
    method reset (line 61) | func (w *responseWriter) reset(writer http.ResponseWriter) {
    method WriteHeader (line 67) | func (w *responseWriter) WriteHeader(code int) {
    method WriteHeaderNow (line 77) | func (w *responseWriter) WriteHeaderNow() {
    method Write (line 84) | func (w *responseWriter) Write(data []byte) (n int, err error) {
    method WriteString (line 91) | func (w *responseWriter) WriteString(s string) (n int, err error) {
    method Status (line 98) | func (w *responseWriter) Status() int {
    method Size (line 102) | func (w *responseWriter) Size() int {
    method Written (line 106) | func (w *responseWriter) Written() bool {
    method Hijack (line 111) | func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
    method CloseNotify (line 124) | func (w *responseWriter) CloseNotify() <-chan bool {
    method Flush (line 129) | func (w *responseWriter) Flush() {
    method Pusher (line 136) | func (w *responseWriter) Pusher() (pusher http.Pusher) {

FILE: response_writer_test.go
  function init (line 32) | func init() {
  function TestResponseWriterUnwrap (line 36) | func TestResponseWriterUnwrap(t *testing.T) {
  function TestResponseWriterReset (line 42) | func TestResponseWriterReset(t *testing.T) {
  function TestResponseWriterWriteHeader (line 56) | func TestResponseWriterWriteHeader(t *testing.T) {
  function TestResponseWriterWriteHeadersNow (line 71) | func TestResponseWriterWriteHeadersNow(t *testing.T) {
  function TestResponseWriterWrite (line 89) | func TestResponseWriterWrite(t *testing.T) {
  function TestResponseWriterHijack (line 110) | func TestResponseWriterHijack(t *testing.T) {
  type mockHijacker (line 129) | type mockHijacker struct
    method Hijack (line 135) | func (m *mockHijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  function TestResponseWriterHijackAfterWrite (line 140) | func TestResponseWriterHijackAfterWrite(t *testing.T) {
  function TestResponseWriterHijackAfterWriteHeaderNow (line 198) | func TestResponseWriterHijackAfterWriteHeaderNow(t *testing.T) {
  function TestResponseWriterFlush (line 255) | func TestResponseWriterFlush(t *testing.T) {
  function TestResponseWriterStatusCode (line 271) | func TestResponseWriterStatusCode(t *testing.T) {
  type mockPusherResponseWriter (line 290) | type mockPusherResponseWriter struct
    method Push (line 294) | func (m *mockPusherResponseWriter) Push(target string, opts *http.Push...
  type nonPusherResponseWriter (line 299) | type nonPusherResponseWriter struct
  function TestPusherWithPusher (line 303) | func TestPusherWithPusher(t *testing.T) {
  function TestPusherWithoutPusher (line 311) | func TestPusherWithoutPusher(t *testing.T) {

FILE: routergroup.go
  type IRouter (line 27) | type IRouter interface
  type IRoutes (line 33) | type IRoutes interface
  type RouterGroup (line 55) | type RouterGroup struct
    method Use (line 65) | func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    method Group (line 72) | func (group *RouterGroup) Group(relativePath string, handlers ...Handl...
    method BasePath (line 82) | func (group *RouterGroup) BasePath() string {
    method handle (line 86) | func (group *RouterGroup) handle(httpMethod, relativePath string, hand...
    method Handle (line 103) | func (group *RouterGroup) Handle(httpMethod, relativePath string, hand...
    method POST (line 111) | func (group *RouterGroup) POST(relativePath string, handlers ...Handle...
    method GET (line 116) | func (group *RouterGroup) GET(relativePath string, handlers ...Handler...
    method DELETE (line 121) | func (group *RouterGroup) DELETE(relativePath string, handlers ...Hand...
    method PATCH (line 126) | func (group *RouterGroup) PATCH(relativePath string, handlers ...Handl...
    method PUT (line 131) | func (group *RouterGroup) PUT(relativePath string, handlers ...Handler...
    method OPTIONS (line 136) | func (group *RouterGroup) OPTIONS(relativePath string, handlers ...Han...
    method HEAD (line 141) | func (group *RouterGroup) HEAD(relativePath string, handlers ...Handle...
    method Any (line 147) | func (group *RouterGroup) Any(relativePath string, handlers ...Handler...
    method Match (line 156) | func (group *RouterGroup) Match(methods []string, relativePath string,...
    method StaticFile (line 166) | func (group *RouterGroup) StaticFile(relativePath, filepath string) IR...
    method StaticFileFS (line 175) | func (group *RouterGroup) StaticFileFS(relativePath, filepath string, ...
    method staticFileHandler (line 181) | func (group *RouterGroup) staticFileHandler(relativePath string, handl...
    method Static (line 197) | func (group *RouterGroup) Static(relativePath, root string) IRoutes {
    method StaticFS (line 203) | func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSy...
    method createStaticHandler (line 216) | func (group *RouterGroup) createStaticHandler(relativePath string, fs ...
    method combineHandlers (line 241) | func (group *RouterGroup) combineHandlers(handlers HandlersChain) Hand...
    method calculateAbsolutePath (line 250) | func (group *RouterGroup) calculateAbsolutePath(relativePath string) s...
    method returnObj (line 254) | func (group *RouterGroup) returnObj() IRoutes {

FILE: routergroup_test.go
  function init (line 16) | func init() {
  function TestRouterGroupBasic (line 20) | func TestRouterGroupBasic(t *testing.T) {
  function TestRouterGroupBasicHandle (line 37) | func TestRouterGroupBasicHandle(t *testing.T) {
  function performRequestInGroup (line 47) | func performRequestInGroup(t *testing.T, method string) {
  function TestRouterGroupInvalidStatic (line 94) | func TestRouterGroupInvalidStatic(t *testing.T) {
  function TestRouterGroupInvalidStaticFile (line 105) | func TestRouterGroupInvalidStaticFile(t *testing.T) {
  function TestRouterGroupInvalidStaticFileFS (line 116) | func TestRouterGroupInvalidStaticFileFS(t *testing.T) {
  function TestRouterGroupTooManyHandlers (line 127) | func TestRouterGroupTooManyHandlers(t *testing.T) {
  function TestRouterGroupBadMethod (line 145) | func TestRouterGroupBadMethod(t *testing.T) {
  function TestRouterGroupPipeline (line 170) | func TestRouterGroupPipeline(t *testing.T) {
  function testRoutesInterface (line 178) | func testRoutesInterface(t *testing.T, r IRoutes) {
  function TestRouterGroupCombineHandlersTooManyHandlers (line 199) | func TestRouterGroupCombineHandlersTooManyHandlers(t *testing.T) {
  function TestRouterGroupCombineHandlersEmptySliceNotNil (line 211) | func TestRouterGroupCombineHandlersEmptySliceNotNil(t *testing.T) {

FILE: routes_test.go
  type header (line 19) | type header struct
  function PerformRequest (line 25) | func PerformRequest(r http.Handler, method, path string, headers ...head...
  function testRouteOK (line 35) | func testRouteOK(method string, t *testing.T) {
  function testRouteNotOK (line 55) | func testRouteNotOK(method string, t *testing.T) {
  function testRouteNotOK2 (line 69) | func testRouteNotOK2(method string, t *testing.T) {
  function TestRouterMethod (line 89) | func TestRouterMethod(t *testing.T) {
  function TestRouterGroupRouteOK (line 109) | func TestRouterGroupRouteOK(t *testing.T) {
  function TestRouteNotOK (line 121) | func TestRouteNotOK(t *testing.T) {
  function TestRouteNotOK2 (line 133) | func TestRouteNotOK2(t *testing.T) {
  function TestRouteRedirectTrailingSlash (line 145) | func TestRouteRedirectTrailingSlash(t *testing.T) {
  function TestRouteRedirectFixedPath (line 249) | func TestRouteRedirectFixedPath(t *testing.T) {
  function TestRouteParamsByName (line 277) | func TestRouteParamsByName(t *testing.T) {
  function TestRouteParamsByNameWithExtraSlash (line 309) | func TestRouteParamsByNameWithExtraSlash(t *testing.T) {
  function TestRouteParamsNotEmpty (line 344) | func TestRouteParamsNotEmpty(t *testing.T) {
  function TestRouteStaticFile (line 381) | func TestRouteStaticFile(t *testing.T) {
  function TestRouteStaticFileFS (line 416) | func TestRouteStaticFileFS(t *testing.T) {
  function TestRouteStaticListingDir (line 450) | func TestRouteStaticListingDir(t *testing.T) {
  function TestRouteStaticNoListing (line 462) | func TestRouteStaticNoListing(t *testing.T) {
  function TestRouterMiddlewareAndStatic (line 472) | func TestRouterMiddlewareAndStatic(t *testing.T) {
  function TestRouteNotAllowedEnabled (line 493) | func TestRouteNotAllowedEnabled(t *testing.T) {
  function TestRouteNotAllowedEnabled2 (line 508) | func TestRouteNotAllowedEnabled2(t *testing.T) {
  function TestRouteNotAllowedEnabled3 (line 518) | func TestRouteNotAllowedEnabled3(t *testing.T) {
  function TestRouteNotAllowedDisabled (line 530) | func TestRouteNotAllowedDisabled(t *testing.T) {
  function TestRouterNotFoundWithRemoveExtraSlash (line 545) | func TestRouterNotFoundWithRemoveExtraSlash(t *testing.T) {
  function TestRouterNotFound (line 568) | func TestRouterNotFound(t *testing.T) {
  function TestRouterStaticFSNotFound (line 635) | func TestRouterStaticFSNotFound(t *testing.T) {
  function TestRouterStaticFSFileNotFound (line 649) | func TestRouterStaticFSFileNotFound(t *testing.T) {
  function TestMiddlewareCalledOnceByRouterStaticFSNotFound (line 660) | func TestMiddlewareCalledOnceByRouterStaticFSNotFound(t *testing.T) {
  function TestRouteRawPath (line 680) | func TestRouteRawPath(t *testing.T) {
  function TestRouteRawPathNoUnescape (line 699) | func TestRouteRawPathNoUnescape(t *testing.T) {
  function TestRouteServeErrorWithWriteHeader (line 719) | func TestRouteServeErrorWithWriteHeader(t *testing.T) {
  function TestRouteContextHoldsFullPath (line 731) | func TestRouteContextHoldsFullPath(t *testing.T) {
  function TestEngineHandleMethodNotAllowedCornerCase (line 774) | func TestEngineHandleMethodNotAllowedCornerCase(t *testing.T) {

FILE: test_helpers.go
  function CreateTestContext (line 17) | func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) {
  function CreateTestContextOnly (line 30) | func CreateTestContextOnly(w http.ResponseWriter, r *Engine) (c *Context) {
  function waitForServerReady (line 39) | func waitForServerReady(url string, maxAttempts int) error {

FILE: testdata/protoexample/test.pb.go
  constant _ (line 18) | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
  constant _ (line 20) | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
  type FOO (line 23) | type FOO
    method Enum (line 39) | func (x FOO) Enum() *FOO {
    method String (line 45) | func (x FOO) String() string {
    method Descriptor (line 49) | func (FOO) Descriptor() protoreflect.EnumDescriptor {
    method Type (line 53) | func (FOO) Type() protoreflect.EnumType {
    method Number (line 57) | func (x FOO) Number() protoreflect.EnumNumber {
    method UnmarshalJSON (line 62) | func (x *FOO) UnmarshalJSON(b []byte) error {
    method EnumDescriptor (line 72) | func (FOO) EnumDescriptor() ([]byte, []int) {
  constant FOO_X (line 26) | FOO_X FOO = 17
  type Test (line 76) | type Test struct
    method Reset (line 92) | func (x *Test) Reset() {
    method String (line 101) | func (x *Test) String() string {
    method ProtoMessage (line 105) | func (*Test) ProtoMessage() {}
    method ProtoReflect (line 107) | func (x *Test) ProtoReflect() protoreflect.Message {
    method Descriptor (line 120) | func (*Test) Descriptor() ([]byte, []int) {
    method GetLabel (line 124) | func (x *Test) GetLabel() string {
    method GetType (line 131) | func (x *Test) GetType() int32 {
    method GetReps (line 138) | func (x *Test) GetReps() []int64 {
    method GetOptionalgroup (line 145) | func (x *Test) GetOptionalgroup() *Test_OptionalGroup {
  constant Default_Test_Type (line 89) | Default_Test_Type = int32(77)
  type Test_OptionalGroup (line 152) | type Test_OptionalGroup struct
    method Reset (line 160) | func (x *Test_OptionalGroup) Reset() {
    method String (line 169) | func (x *Test_OptionalGroup) String() string {
    method ProtoMessage (line 173) | func (*Test_OptionalGroup) ProtoMessage() {}
    method ProtoReflect (line 175) | func (x *Test_OptionalGroup) ProtoReflect() protoreflect.Message {
    method Descriptor (line 188) | func (*Test_OptionalGroup) Descriptor() ([]byte, []int) {
    method GetRequiredField (line 192) | func (x *Test_OptionalGroup) GetRequiredField() string {
  function file_test_proto_rawDescGZIP (line 225) | func file_test_proto_rawDescGZIP() []byte {
  function init (line 248) | func init() { file_test_proto_init() }
  function file_test_proto_init (line 249) | func file_test_proto_init() {

FILE: tree.go
  type Param (line 17) | type Param struct
  type Params (line 25) | type Params
    method Get (line 29) | func (ps Params) Get(name string) (string, bool) {
    method ByName (line 40) | func (ps Params) ByName(name string) (va string) {
  type methodTree (line 45) | type methodTree struct
  type methodTrees (line 50) | type methodTrees
    method get (line 52) | func (trees methodTrees) get(method string) *node {
  function longestCommonPrefix (line 61) | func longestCommonPrefix(a, b string) int {
  function countParams (line 80) | func countParams(path string) uint16 {
  function countSections (line 86) | func countSections(path string) uint16 {
  type nodeType (line 90) | type nodeType
  constant static (line 93) | static nodeType = iota
  constant root (line 94) | root
  constant param (line 95) | param
  constant catchAll (line 96) | catchAll
  type node (line 99) | type node struct
    method addChild (line 71) | func (n *node) addChild(child *node) {
    method incrementChildPrio (line 111) | func (n *node) incrementChildPrio(pos int) int {
    method addRoute (line 135) | func (n *node) addRoute(path string, handlers HandlersChain) {
    method insertChild (line 288) | func (n *node) insertChild(path string, fullPath string, handlers Hand...
    method getValue (line 418) | func (n *node) getValue(path string, params *Params, skippedNodes *[]s...
    method findCaseInsensitivePath (line 671) | func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash b...
    method findCaseInsensitivePathRec (line 703) | func (n *node) findCaseInsensitivePathRec(path string, ciPath []byte, ...
  function findWildcard (line 253) | func findWildcard(path string) (wildcard string, i int, valid bool) {
  type nodeValue (line 400) | type nodeValue struct
  type skippedNode (line 407) | type skippedNode struct
  function shiftNRuneBytes (line 687) | func shiftNRuneBytes(rb [4]byte, n int) [4]byte {

FILE: tree_test.go
  function fakeHandler (line 18) | func fakeHandler(val string) HandlersChain {
  type testRequests (line 24) | type testRequests
  function getParams (line 31) | func getParams() *Params {
  function getSkippedNodes (line 36) | func getSkippedNodes() *[]skippedNode {
  function checkRequests (line 41) | func checkRequests(t *testing.T, tree *node, requests testRequests, unes...
  function checkPriorities (line 72) | func checkPriorities(t *testing.T, n *node) uint32 {
  function TestCountParams (line 92) | func TestCountParams(t *testing.T) {
  function TestTreeAddAndGet (line 101) | func TestTreeAddAndGet(t *testing.T) {
  function TestTreeWildcard (line 138) | func TestTreeWildcard(t *testing.T) {
  function TestUnescapeParameters (line 325) | func TestUnescapeParameters(t *testing.T) {
  function catchPanic (line 362) | func catchPanic(testFunc func()) (recv any) {
  type testRoute (line 371) | type testRoute struct
  function testRoutes (line 376) | func testRoutes(t *testing.T, routes []testRoute) {
  function TestTreeWildcardConflict (line 394) | func TestTreeWildcardConflict(t *testing.T) {
  function TestCatchAllAfterSlash (line 431) | func TestCatchAllAfterSlash(t *testing.T) {
  function TestTreeChildConflict (line 438) | func TestTreeChildConflict(t *testing.T) {
  function TestTreeDuplicatePath (line 457) | func TestTreeDuplicatePath(t *testing.T) {
  function TestEmptyWildcardName (line 495) | func TestEmptyWildcardName(t *testing.T) {
  function TestTreeCatchAllConflict (line 514) | func TestTreeCatchAllConflict(t *testing.T) {
  function TestTreeCatchAllConflictRoot (line 525) | func TestTreeCatchAllConflictRoot(t *testing.T) {
  function TestTreeCatchMaxParams (line 533) | func TestTreeCatchMaxParams(t *testing.T) {
  function TestTreeDoubleWildcard (line 539) | func TestTreeDoubleWildcard(t *testing.T) {
  function TestTreeTrailingSlashRedirect (line 570) | func TestTreeTrailingSlashRedirect(t *testing.T) {
  function TestTreeRootTrailingSlashRedirect (line 676) | func TestTreeRootTrailingSlashRedirect(t *testing.T) {
  function TestRedirectTrailingSlash (line 694) | func TestRedirectTrailingSlash(t *testing.T) {
  function TestTreeFindCaseInsensitivePath (line 714) | func TestTreeFindCaseInsensitivePath(t *testing.T) {
  function TestTreeInvalidNodeType (line 874) | func TestTreeInvalidNodeType(t *testing.T) {
  function TestTreeInvalidParamsType (line 901) | func TestTreeInvalidParamsType(t *testing.T) {
  function TestTreeExpandParamsCapacity (line 914) | func TestTreeExpandParamsCapacity(t *testing.T) {
  function TestTreeWildcardConflictEx (line 942) | func TestTreeWildcardConflictEx(t *testing.T) {
  function TestTreeInvalidEscape (line 980) | func TestTreeInvalidEscape(t *testing.T) {
  function TestWildcardInvalidSlash (line 997) | func TestWildcardInvalidSlash(t *testing.T) {
  function TestTreeFindCaseInsensitivePathWithMultipleChildrenAndWildcard (line 1022) | func TestTreeFindCaseInsensitivePathWithMultipleChildrenAndWildcard(t *t...
  function TestTreeFindCaseInsensitivePathWildcardParamAndStaticChild (line 1066) | func TestTreeFindCaseInsensitivePathWildcardParamAndStaticChild(t *testi...

FILE: utils.go
  constant BindKey (line 20) | BindKey = "_gin-gonic/gin/bindkey"
  constant localhostIP (line 23) | localhostIP = "127.0.0.1"
  constant localhostIPv6 (line 26) | localhostIPv6 = "::1"
  function Bind (line 29) | func Bind(val any) HandlerFunc {
  function WrapF (line 47) | func WrapF(f http.HandlerFunc) HandlerFunc {
  function WrapH (line 54) | func WrapH(h http.Handler) HandlerFunc {
  type H (line 61) | type H
    method MarshalXML (line 64) | func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  function assert1 (line 85) | func assert1(guard bool, text string) {
  function filterFlags (line 91) | func filterFlags(content string) string {
  function chooseData (line 100) | func chooseData(custom, wildcard any) any {
  function parseAccept (line 110) | func parseAccept(acceptHeader string) []string {
  function lastChar (line 124) | func lastChar(str string) uint8 {
  function nameOfFunction (line 131) | func nameOfFunction(f any) string {
  function joinPaths (line 135) | func joinPaths(absolutePath, relativePath string) string {
  function resolveAddress (line 147) | func resolveAddress(addr []string) string {
  function isASCII (line 164) | func isASCII(s string) bool {
  function safeInt8 (line 174) | func safeInt8(n int) int8 {
  function safeUint16 (line 182) | func safeUint16(n int) uint16 {

FILE: utils_test.go
  function init (line 19) | func init() {
  function BenchmarkParseAccept (line 23) | func BenchmarkParseAccept(b *testing.B) {
  type testStruct (line 29) | type testStruct struct
    method ServeHTTP (line 33) | func (t *testStruct) ServeHTTP(w http.ResponseWriter, req *http.Reques...
  function TestWrap (line 40) | func TestWrap(t *testing.T) {
  function TestLastChar (line 59) | func TestLastChar(t *testing.T) {
  function TestParseAccept (line 65) | func TestParseAccept(t *testing.T) {
  function TestChooseData (line 74) | func TestChooseData(t *testing.T) {
  function TestFilterFlags (line 82) | func TestFilterFlags(t *testing.T) {
  function TestFunctionName (line 90) | func TestFunctionName(t *testing.T) {
  function somefunction (line 94) | func somefunction() {
  function TestJoinPaths (line 98) | func TestJoinPaths(t *testing.T) {
  type bindTestStruct (line 111) | type bindTestStruct struct
  function TestBindMiddleware (line 116) | func TestBindMiddleware(t *testing.T) {
  function TestMarshalXMLforH (line 138) | func TestMarshalXMLforH(t *testing.T) {
  function TestMarshalXMLforHSuccess (line 149) | func TestMarshalXMLforHSuccess(t *testing.T) {
  function TestIsASCII (line 160) | func TestIsASCII(t *testing.T) {
  function TestSafeInt8 (line 165) | func TestSafeInt8(t *testing.T) {
  function TestSafeUint16 (line 170) | func TestSafeUint16(t *testing.T) {

FILE: version.go
  constant Version (line 8) | Version = "v1.12.0"
Condensed preview — 130 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (937K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yaml",
    "chars": 2109,
    "preview": "name: Bug Report\ndescription: Found something you weren't expecting? Report it here!\nlabels: [\"type/bug\"]\nbody:\n  - type"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 469,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: Go.dev API Documentation\n    url: https://pkg.go.dev/github.com/gin"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yaml",
    "chars": 690,
    "preview": "name: Feature Request\ndescription: Got an idea for a feature that Gin doesn't have currently?  Submit your idea here!\nla"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 436,
    "preview": "# Pull Request Checklist\n\nPlease ensure your pull request meets the following requirements:\n\n- [ ] Open your pull reques"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 254,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: gomod\n    directory: /\n    schedule:\n      interval: daily\n  - package-ecosys"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "chars": 1561,
    "preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
  },
  {
    "path": ".github/workflows/gin.yml",
    "chars": 1967,
    "preview": "name: Run Tests\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\npermissions:\n  c"
  },
  {
    "path": ".github/workflows/goreleaser.yml",
    "chars": 890,
    "preview": "name: Goreleaser\n\non:\n  push:\n    tags:\n      - \"*\"\n\npermissions:\n  contents: write\n\njobs:\n  goreleaser:\n    runs-on: ub"
  },
  {
    "path": ".github/workflows/trivy-scan.yml",
    "chars": 1410,
    "preview": "name: Trivy Security Scan\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n  sched"
  },
  {
    "path": ".gitignore",
    "chars": 110,
    "preview": "vendor/*\n!vendor/vendor.json\ncoverage.out\ncount.out\ntest\nprofile.out\ntmp.out\n\n# Develop tools\n.idea/\n.vscode/\n"
  },
  {
    "path": ".golangci.yml",
    "chars": 1343,
    "preview": "version: \"2\"\nlinters:\n  enable:\n    - asciicheck\n    - copyloopvar\n    - dogsled\n    - durationcheck\n    - errorlint\n   "
  },
  {
    "path": ".goreleaser.yaml",
    "chars": 1700,
    "preview": "project_name: gin\n\nbuilds:\n  - # If true, skip the build.\n    # Useful for library projects.\n    # Default is false\n    "
  },
  {
    "path": "BENCHMARKS.md",
    "chars": 12038,
    "preview": "# Gin Benchmark Report\n\n**Machine:** Apple M4 Pro\n**OS:** macOS (Darwin 25.3.0), arm64\n**Date:** March 15th, 2026\n**Gin "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 50830,
    "preview": "# Gin ChangeLog\n\n## Gin v1.12.0\n\n### Features\n\n- feat(render): add bson protocol ([#4145](https://github.com/gin-gonic/g"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3219,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2100,
    "preview": "# Contributing\n\nWe welcome both issue reports and pull requests! Please follow these guidelines to help maintainers resp"
  },
  {
    "path": "LICENSE",
    "chars": 1098,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014-present Manuel Martínez-Almeida\n\nPermission is hereby granted, free of charge,"
  },
  {
    "path": "Makefile",
    "chars": 3010,
    "preview": "GO ?= go\nGOFMT ?= gofmt \"-s\"\nGO_VERSION=$(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)\nPACKAGES ?= "
  },
  {
    "path": "README.md",
    "chars": 11756,
    "preview": "# Gin Web Framework\n\n<img align=\"right\" width=\"159px\" src=\"https://raw.githubusercontent.com/gin-gonic/logo/master/color"
  },
  {
    "path": "auth.go",
    "chars": 3838,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "auth_test.go",
    "chars": 5074,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "benchmarks_test.go",
    "chars": 3962,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/binding.go",
    "chars": 4294,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/binding_msgpack_test.go",
    "chars": 1423,
    "preview": "// Copyright 2020 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/binding_nomsgpack.go",
    "chars": 3822,
    "preview": "// Copyright 2020 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/binding_test.go",
    "chars": 39518,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/bson.go",
    "chars": 580,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/default_validator.go",
    "chars": 2294,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/default_validator_benchmark_test.go",
    "chars": 494,
    "preview": "// Copyright 2022 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/default_validator_test.go",
    "chars": 3591,
    "preview": "// Copyright 2020 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/form.go",
    "chars": 1357,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/form_mapping.go",
    "chars": 13602,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/form_mapping_benchmark_test.go",
    "chars": 1468,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/form_mapping_test.go",
    "chars": 34152,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/header.go",
    "chars": 868,
    "preview": "// Copyright 2022 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/json.go",
    "chars": 1543,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/json_test.go",
    "chars": 5524,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/msgpack.go",
    "chars": 768,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/msgpack_test.go",
    "chars": 785,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/multipart_form_mapping.go",
    "chars": 2244,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/multipart_form_mapping_test.go",
    "chars": 3794,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/plain.go",
    "chars": 868,
    "preview": "package binding\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"reflect\"\n\n\t\"github.com/gin-gonic/gin/internal/bytesconv\"\n)\n\ntype pl"
  },
  {
    "path": "binding/protobuf.go",
    "chars": 923,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/query.go",
    "chars": 460,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/toml.go",
    "chars": 698,
    "preview": "// Copyright 2022 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/toml_test.go",
    "chars": 503,
    "preview": "// Copyright 2022 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/uri.go",
    "chars": 399,
    "preview": "// Copyright 2018 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/validate_test.go",
    "chars": 6125,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/xml.go",
    "chars": 677,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "binding/xml_test.go",
    "chars": 560,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/yaml.go",
    "chars": 691,
    "preview": "// Copyright 2018 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "binding/yaml_test.go",
    "chars": 480,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "codec/json/api.go",
    "chars": 1942,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "codec/json/go_json.go",
    "chars": 898,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "codec/json/json.go",
    "chars": 919,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "codec/json/jsoniter.go",
    "chars": 985,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "codec/json/sonic.go",
    "chars": 953,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "codecov.yml",
    "chars": 188,
    "preview": "coverage:\n  require_ci_to_pass: true\n\n  status:\n    project:\n      default:\n        target: 99%\n        threshold: 99%\n\n"
  },
  {
    "path": "context.go",
    "chars": 46437,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "context_appengine.go",
    "chars": 261,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "context_file_test.go",
    "chars": 933,
    "preview": "package gin\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// TestConte"
  },
  {
    "path": "context_test.go",
    "chars": 112677,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "debug.go",
    "chars": 3000,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "debug_test.go",
    "chars": 5413,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "deprecated.go",
    "chars": 762,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "deprecated_test.go",
    "chars": 780,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "doc.go",
    "chars": 414,
    "preview": "/*\nPackage gin implements a HTTP web framework called gin.\n\nSee https://gin-gonic.com/ for more information about gin.\n\n"
  },
  {
    "path": "docs/doc.md",
    "chars": 69011,
    "preview": "# Gin Quick Start\n\n## Contents\n\n- [Build Tags](#build-tags)\n  - [Build with json replacement](#build-with-json-replaceme"
  },
  {
    "path": "errors.go",
    "chars": 3944,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "errors_test.go",
    "chars": 4297,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "examples/README.md",
    "chars": 140,
    "preview": "# Gin Examples\n\n⚠️  **NOTICE:** All gin examples have been moved as standalone repository to [here](https://github.com/g"
  },
  {
    "path": "fs.go",
    "chars": 1396,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "fs_test.go",
    "chars": 1395,
    "preview": "package gin\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretch"
  },
  {
    "path": "gin.go",
    "chars": 27227,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "ginS/README.md",
    "chars": 250,
    "preview": "# Gin Default Server\n\nThis is API experiment for Gin.\n\n```go\npackage main\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github"
  },
  {
    "path": "ginS/gins.go",
    "chars": 5654,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "ginS/gins_test.go",
    "chars": 5862,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "gin_integration_test.go",
    "chars": 23533,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gin_test.go",
    "chars": 28333,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "githubapi_test.go",
    "chars": 17383,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "go.mod",
    "chars": 1600,
    "preview": "module github.com/gin-gonic/gin\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/bytedance/sonic v1.15.0\n\tgithub.com/gin-contrib/sse v1"
  },
  {
    "path": "go.sum",
    "chars": 8481,
    "preview": "github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=\ngithub.com/bytedance/gopkg v0.1.3/go.m"
  },
  {
    "path": "internal/bytesconv/bytesconv.go",
    "chars": 719,
    "preview": "// Copyright 2023 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "internal/bytesconv/bytesconv_test.go",
    "chars": 2810,
    "preview": "// Copyright 2020 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "internal/fs/fs.go",
    "chars": 362,
    "preview": "package fs\n\nimport (\n\t\"io/fs\"\n\t\"net/http\"\n)\n\n// FileSystem implements an [fs.FS].\ntype FileSystem struct {\n\thttp.FileSys"
  },
  {
    "path": "internal/fs/fs_test.go",
    "chars": 894,
    "preview": "package fs\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr"
  },
  {
    "path": "logger.go",
    "chars": 8070,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "logger_test.go",
    "chars": 15933,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "middleware_test.go",
    "chars": 5371,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "mode.go",
    "chars": 2456,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "mode_test.go",
    "chars": 1635,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "path.go",
    "chars": 4911,
    "preview": "// Copyright 2013 Julien Schmidt. All rights reserved.\n// Based on the path package, Copyright 2009 The Go Authors.\n// U"
  },
  {
    "path": "path_test.go",
    "chars": 3726,
    "preview": "// Copyright 2013 Julien Schmidt. All rights reserved.\n// Based on the path package, Copyright 2009 The Go Authors.\n// U"
  },
  {
    "path": "recovery.go",
    "chars": 5718,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "recovery_test.go",
    "chars": 10918,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/bson.go",
    "chars": 790,
    "preview": "// Copyright 2025 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "render/data.go",
    "chars": 742,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/html.go",
    "chars": 2875,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/json.go",
    "chars": 5013,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/msgpack.go",
    "chars": 1175,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/pdf.go",
    "chars": 651,
    "preview": "// Copyright 2026 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "render/protobuf.go",
    "chars": 852,
    "preview": "// Copyright 2018 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "render/reader.go",
    "chars": 1195,
    "preview": "// Copyright 2018 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "render/reader_test.go",
    "chars": 504,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "render/redirect.go",
    "chars": 904,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/render.go",
    "chars": 1203,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/render_msgpack_test.go",
    "chars": 1902,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/render_test.go",
    "chars": 20855,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/text.go",
    "chars": 1091,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/toml.go",
    "chars": 820,
    "preview": "// Copyright 2022 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "render/xml.go",
    "chars": 730,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "render/yaml.go",
    "chars": 821,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "response_writer.go",
    "chars": 3263,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "response_writer_test.go",
    "chars": 9282,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "routergroup.go",
    "chars": 9279,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "routergroup_test.go",
    "chars": 5970,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "routes_test.go",
    "chars": 24774,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "test_helpers.go",
    "chars": 1902,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "testdata/certificate/cert.pem",
    "chars": 1086,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIC9DCCAdygAwIBAgIQUNSK+OxWHYYFxHVJV0IlpDANBgkqhkiG9w0BAQsFADAS\nMRAwDgYDVQQKEwdBY21lIENvMB4"
  },
  {
    "path": "testdata/certificate/key.pem",
    "chars": 1675,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAqbKP9hmkPn0GnLjDep/pXMzD25QGxan4g/iSXvPlyYYdhQef\n9iilMse9HbcYAHXanoqblBb"
  },
  {
    "path": "testdata/protoexample/test.pb.go",
    "chars": 8374,
    "preview": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.27.0\n// \tprotoc        v3.15.8\n// sou"
  },
  {
    "path": "testdata/protoexample/test.proto",
    "chars": 239,
    "preview": "package protoexample;\n\nenum FOO {X=17;};\n\nmessage Test {\n   required string label = 1;\n   optional int32 type = 2[defaul"
  },
  {
    "path": "testdata/template/hello.tmpl",
    "chars": 26,
    "preview": "<h1>Hello {[{.name}]}</h1>"
  },
  {
    "path": "testdata/template/raw.tmpl",
    "chars": 31,
    "preview": "Date: {[{.now | formatAsDate}]}"
  },
  {
    "path": "testdata/test_file.txt",
    "chars": 124,
    "preview": "This is a test file for Context.File() method testing.\nIt contains some sample content to verify file serving functional"
  },
  {
    "path": "tree.go",
    "chars": 24381,
    "preview": "// Copyright 2013 Julien Schmidt. All rights reserved.\n// Use of this source code is governed by a BSD-style license tha"
  },
  {
    "path": "tree_test.go",
    "chars": 35882,
    "preview": "// Copyright 2013 Julien Schmidt. All rights reserved.\n// Use of this source code is governed by a BSD-style license tha"
  },
  {
    "path": "utils.go",
    "chars": 4117,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "utils_test.go",
    "chars": 4589,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "version.go",
    "chars": 249,
    "preview": "// Copyright 2018 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  }
]

About this extraction

This page contains the full source code of the gin-gonic/gin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 130 files (840.2 KB), approximately 247.7k tokens, and a symbol index with 1590 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!