chore: migrate to gitea
This commit is contained in:
25
vendor/github.com/gin-contrib/cors/.gitignore
generated
vendored
Normal file
25
vendor/github.com/gin-contrib/cors/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
_obj
|
||||
_test
|
||||
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
coverage.out
|
||||
|
||||
.idea
|
||||
50
vendor/github.com/gin-contrib/cors/.golangci.yml
generated
vendored
Normal file
50
vendor/github.com/gin-contrib/cors/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
version: "2"
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- bodyclose
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- exhaustive
|
||||
- gochecknoinits
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- noctx
|
||||
- nolintlint
|
||||
- rowserrcheck
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- whitespace
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
28
vendor/github.com/gin-contrib/cors/.goreleaser.yaml
generated
vendored
Normal file
28
vendor/github.com/gin-contrib/cors/.goreleaser.yaml
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
builds:
|
||||
- # If true, skip the build.
|
||||
# Useful for library projects.
|
||||
# Default is false
|
||||
skip: true
|
||||
|
||||
changelog:
|
||||
use: github
|
||||
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
|
||||
21
vendor/github.com/gin-contrib/cors/LICENSE
generated
vendored
Normal file
21
vendor/github.com/gin-contrib/cors/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Gin-Gonic
|
||||
|
||||
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.
|
||||
246
vendor/github.com/gin-contrib/cors/README.md
generated
vendored
Normal file
246
vendor/github.com/gin-contrib/cors/README.md
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
# gin-contrib/cors
|
||||
|
||||
[](https://github.com/gin-contrib/cors/actions/workflows/go.yml)
|
||||
[](https://codecov.io/gh/gin-contrib/cors)
|
||||
[](https://goreportcard.com/report/github.com/gin-contrib/cors)
|
||||
[](https://godoc.org/github.com/gin-contrib/cors)
|
||||
|
||||
- [gin-contrib/cors](#gin-contribcors)
|
||||
- [Overview](#overview)
|
||||
- [Installation](#installation)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Advanced Usage](#advanced-usage)
|
||||
- [Custom Configuration](#custom-configuration)
|
||||
- [DefaultConfig Reference](#defaultconfig-reference)
|
||||
- [Default() Convenience](#default-convenience)
|
||||
- [Configuration Reference](#configuration-reference)
|
||||
- [Notes on Configuration](#notes-on-configuration)
|
||||
- [Examples](#examples)
|
||||
- [Advanced Options](#advanced-options)
|
||||
- [Custom Origin Validation](#custom-origin-validation)
|
||||
- [With Gin Context](#with-gin-context)
|
||||
- [Helper Methods](#helper-methods)
|
||||
- [Validation \& Error Handling](#validation--error-handling)
|
||||
- [Important Notes](#important-notes)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
**CORS (Cross-Origin Resource Sharing)** middleware for [Gin](https://github.com/gin-gonic/gin).
|
||||
|
||||
- Enables flexible CORS handling for your Gin-based APIs.
|
||||
- Highly configurable: origins, methods, headers, credentials, and more.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
go get github.com/gin-contrib/cors
|
||||
```
|
||||
|
||||
Import in your Go code:
|
||||
|
||||
```go
|
||||
import "github.com/gin-contrib/cors"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
Allow all origins (default):
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.Use(cors.Default()) // All origins allowed by default
|
||||
router.Run()
|
||||
}
|
||||
```
|
||||
|
||||
> ⚠️ **Warning:** Allowing all origins disables cookies for clients. For credentialed requests, **do not** allow all origins.
|
||||
|
||||
---
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Configuration
|
||||
|
||||
Configure allowed origins, methods, headers, and more:
|
||||
|
||||
```go
|
||||
import (
|
||||
"time"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
router.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"https://foo.com"},
|
||||
AllowMethods: []string{"PUT", "PATCH"},
|
||||
AllowHeaders: []string{"Origin"},
|
||||
ExposeHeaders: []string{"Content-Length"},
|
||||
AllowCredentials: true,
|
||||
AllowOriginFunc: func(origin string) bool {
|
||||
return origin == "https://github.com"
|
||||
},
|
||||
MaxAge: 12 * time.Hour,
|
||||
}))
|
||||
router.Run()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DefaultConfig Reference
|
||||
|
||||
Start with library defaults and customize as needed:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
config := cors.DefaultConfig()
|
||||
config.AllowOrigins = []string{"http://google.com"}
|
||||
// config.AllowOrigins = []string{"http://google.com", "http://facebook.com"}
|
||||
// config.AllowAllOrigins = true
|
||||
|
||||
router.Use(cors.New(config))
|
||||
router.Run()
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** `Default()` allows all origins, but `DefaultConfig()` does **not**. To allow all origins, set `AllowAllOrigins = true`.
|
||||
|
||||
---
|
||||
|
||||
### Default() Convenience
|
||||
|
||||
Enable all origins with a single call:
|
||||
|
||||
```go
|
||||
router.Use(cors.Default()) // Equivalent to AllowAllOrigins = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
The middleware is controlled via the `cors.Config` struct. All fields are optional unless otherwise stated.
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------------------------------|-----------------------------|-----------------------------------------------------------|-----------------------------------------------------------------------------------------------|
|
||||
| `AllowAllOrigins` | `bool` | `false` | If true, allows all origins. Credentials **cannot** be used. |
|
||||
| `AllowOrigins` | `[]string` | `[]` | List of allowed origins. Supports exact match, `*`, and wildcards. |
|
||||
| `AllowOriginFunc` | `func(string) bool` | `nil` | Custom function to validate origin. If set, `AllowOrigins` is ignored. |
|
||||
| `AllowOriginWithContextFunc` | `func(*gin.Context,string)bool` | `nil` | Like `AllowOriginFunc`, but with request context. |
|
||||
| `AllowMethods` | `[]string` | `[]string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}` | Allowed HTTP methods. |
|
||||
| `AllowPrivateNetwork` | `bool` | `false` | Adds [Private Network Access](https://wicg.github.io/private-network-access/) CORS header. |
|
||||
| `AllowHeaders` | `[]string` | `[]` | List of non-simple headers permitted in requests. |
|
||||
| `AllowCredentials` | `bool` | `false` | Allow cookies, HTTP auth, or client certs. Only if precise origins are used. |
|
||||
| `ExposeHeaders` | `[]string` | `[]` | Headers exposed to the browser. |
|
||||
| `MaxAge` | `time.Duration` | `12 * time.Hour` | Cache time for preflight requests. |
|
||||
| `AllowWildcard` | `bool` | `false` | Enables wildcards in origins (e.g. `https://*.example.com`). |
|
||||
| `AllowBrowserExtensions` | `bool` | `false` | Allow browser extension schemes as origins (e.g. `chrome-extension://`). |
|
||||
| `CustomSchemas` | `[]string` | `nil` | Additional allowed URI schemes (e.g. `tauri://`). |
|
||||
| `AllowWebSockets` | `bool` | `false` | Allow `ws://` and `wss://` schemas. |
|
||||
| `AllowFiles` | `bool` | `false` | Allow `file://` origins (dangerous; use only if necessary). |
|
||||
| `OptionsResponseStatusCode` | `int` | `204` | Custom status code for `OPTIONS` responses. |
|
||||
|
||||
---
|
||||
|
||||
### Notes on Configuration
|
||||
|
||||
- Only one of `AllowAllOrigins`, `AllowOrigins`, `AllowOriginFunc`, or `AllowOriginWithContextFunc` should be set.
|
||||
- If `AllowAllOrigins` is true, other origin settings are ignored and credentialed requests are not allowed.
|
||||
- If `AllowWildcard` is enabled, only one `*` is allowed per origin string.
|
||||
- Use `AllowBrowserExtensions`, `AllowWebSockets`, or `AllowFiles` to permit non-HTTP(s) protocols as origins.
|
||||
- Custom schemas allow, for example, usage in desktop apps via custom URI schemes (`tauri://`, etc.).
|
||||
- If both `AllowOriginFunc` and `AllowOriginWithContextFunc` are set, the context-specific function is preferred.
|
||||
|
||||
---
|
||||
|
||||
### Examples
|
||||
|
||||
#### Advanced Options
|
||||
|
||||
```go
|
||||
config := cors.Config{
|
||||
AllowOrigins: []string{"https://*.foo.com", "https://bar.com"},
|
||||
AllowWildcard: true,
|
||||
AllowMethods: []string{"GET", "POST"},
|
||||
AllowHeaders: []string{"Authorization", "Content-Type"},
|
||||
AllowCredentials: true,
|
||||
AllowBrowserExtensions: true,
|
||||
AllowWebSockets: true,
|
||||
AllowFiles: false,
|
||||
CustomSchemas: []string{"tauri://"},
|
||||
MaxAge: 24 * time.Hour,
|
||||
ExposeHeaders: []string{"X-Custom-Header"},
|
||||
AllowPrivateNetwork: true,
|
||||
}
|
||||
```
|
||||
|
||||
#### Custom Origin Validation
|
||||
|
||||
```go
|
||||
config := cors.Config{
|
||||
AllowOriginFunc: func(origin string) bool {
|
||||
// Allow any github.com subdomain or a custom rule
|
||||
return strings.HasSuffix(origin, "github.com")
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
#### With Gin Context
|
||||
|
||||
```go
|
||||
config := cors.Config{
|
||||
AllowOriginWithContextFunc: func(c *gin.Context, origin string) bool {
|
||||
// Allow only if a certain header is present
|
||||
return c.Request.Header.Get("X-Allow-CORS") == "yes"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Helper Methods
|
||||
|
||||
Dynamically add methods or headers to the config:
|
||||
|
||||
```go
|
||||
config.AddAllowMethods("DELETE", "OPTIONS")
|
||||
config.AddAllowHeaders("X-My-Header")
|
||||
config.AddExposeHeaders("X-Other-Header")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation & Error Handling
|
||||
|
||||
- Calling `Validate()` on a `Config` checks for misconfiguration (called internally).
|
||||
- If `AllowAllOrigins` is set, you cannot also set `AllowOrigins` or any `AllowOriginFunc`.
|
||||
- If neither `AllowAllOrigins`, `AllowOriginFunc`, nor `AllowOrigins` is set, an error is raised.
|
||||
- If an `AllowOrigin` contains a wildcard but `AllowWildcard` is not enabled, or more than one `*` is present, a panic is triggered.
|
||||
- Invalid origin schemas or unsupported wildcards are rejected.
|
||||
|
||||
---
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Enabling all origins disables cookies:** When `AllowAllOrigins` is enabled, Gin cannot set cookies for clients. If you need credential sharing (cookies, authentication headers), **do not** allow all origins.
|
||||
- For detailed documentation and configuration options, see the [GoDoc](https://godoc.org/github.com/gin-contrib/cors).
|
||||
167
vendor/github.com/gin-contrib/cors/config.go
generated
vendored
Normal file
167
vendor/github.com/gin-contrib/cors/config.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
package cors
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type cors struct {
|
||||
allowAllOrigins bool
|
||||
allowCredentials bool
|
||||
allowOriginFunc func(string) bool
|
||||
allowOriginWithContextFunc func(*gin.Context, string) bool
|
||||
allowOrigins []string
|
||||
normalHeaders http.Header
|
||||
preflightHeaders http.Header
|
||||
wildcardOrigins [][]string
|
||||
optionsResponseStatusCode int
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultSchemas = []string{
|
||||
"http://",
|
||||
"https://",
|
||||
}
|
||||
ExtensionSchemas = []string{
|
||||
"chrome-extension://",
|
||||
"safari-extension://",
|
||||
"moz-extension://",
|
||||
"ms-browser-extension://",
|
||||
}
|
||||
FileSchemas = []string{
|
||||
"file://",
|
||||
}
|
||||
WebSocketSchemas = []string{
|
||||
"ws://",
|
||||
"wss://",
|
||||
}
|
||||
)
|
||||
|
||||
func newCors(config Config) *cors {
|
||||
if err := config.Validate(); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
for _, origin := range config.AllowOrigins {
|
||||
if origin == "*" {
|
||||
config.AllowAllOrigins = true
|
||||
}
|
||||
}
|
||||
|
||||
if config.OptionsResponseStatusCode == 0 {
|
||||
config.OptionsResponseStatusCode = http.StatusNoContent
|
||||
}
|
||||
|
||||
return &cors{
|
||||
allowOriginFunc: config.AllowOriginFunc,
|
||||
allowOriginWithContextFunc: config.AllowOriginWithContextFunc,
|
||||
allowAllOrigins: config.AllowAllOrigins,
|
||||
allowCredentials: config.AllowCredentials,
|
||||
allowOrigins: normalize(config.AllowOrigins),
|
||||
normalHeaders: generateNormalHeaders(config),
|
||||
preflightHeaders: generatePreflightHeaders(config),
|
||||
wildcardOrigins: config.parseWildcardRules(),
|
||||
optionsResponseStatusCode: config.OptionsResponseStatusCode,
|
||||
}
|
||||
}
|
||||
|
||||
func (cors *cors) applyCors(c *gin.Context) {
|
||||
origin := c.Request.Header.Get("Origin")
|
||||
if len(origin) == 0 {
|
||||
// request is not a CORS request
|
||||
return
|
||||
}
|
||||
host := c.Request.Host
|
||||
|
||||
if origin == "http://"+host || origin == "https://"+host {
|
||||
// request is not a CORS request but have origin header.
|
||||
// for example, use fetch api
|
||||
return
|
||||
}
|
||||
|
||||
if !cors.isOriginValid(c, origin) {
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if c.Request.Method == http.MethodOptions {
|
||||
cors.handlePreflight(c)
|
||||
defer c.AbortWithStatus(cors.optionsResponseStatusCode)
|
||||
} else {
|
||||
cors.handleNormal(c)
|
||||
}
|
||||
|
||||
if !cors.allowAllOrigins {
|
||||
c.Header("Access-Control-Allow-Origin", origin)
|
||||
}
|
||||
}
|
||||
|
||||
func (cors *cors) validateWildcardOrigin(origin string) bool {
|
||||
for _, w := range cors.wildcardOrigins {
|
||||
if w[0] == "*" && strings.HasSuffix(origin, w[1]) {
|
||||
return true
|
||||
}
|
||||
if w[1] == "*" && strings.HasPrefix(origin, w[0]) {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(origin, w[0]) && strings.HasSuffix(origin, w[1]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (cors *cors) isOriginValid(c *gin.Context, origin string) bool {
|
||||
valid := cors.validateOrigin(origin)
|
||||
if !valid && cors.allowOriginWithContextFunc != nil {
|
||||
valid = cors.allowOriginWithContextFunc(c, origin)
|
||||
}
|
||||
return valid
|
||||
}
|
||||
|
||||
var originRegex = regexp.MustCompile(`^/(.+)/[gimuy]?$`)
|
||||
|
||||
func (cors *cors) validateOrigin(origin string) bool {
|
||||
if cors.allowAllOrigins {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, value := range cors.allowOrigins {
|
||||
if !originRegex.MatchString(value) && value == origin {
|
||||
return true
|
||||
}
|
||||
|
||||
if originRegex.MatchString(value) &&
|
||||
regexp.MustCompile(originRegex.FindStringSubmatch(value)[1]).MatchString(origin) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if len(cors.wildcardOrigins) > 0 && cors.validateWildcardOrigin(origin) {
|
||||
return true
|
||||
}
|
||||
|
||||
if cors.allowOriginFunc != nil {
|
||||
return cors.allowOriginFunc(origin)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (cors *cors) handlePreflight(c *gin.Context) {
|
||||
header := c.Writer.Header()
|
||||
for key, value := range cors.preflightHeaders {
|
||||
header[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
func (cors *cors) handleNormal(c *gin.Context) {
|
||||
header := c.Writer.Header()
|
||||
for key, value := range cors.normalHeaders {
|
||||
header[key] = value
|
||||
}
|
||||
}
|
||||
208
vendor/github.com/gin-contrib/cors/cors.go
generated
vendored
Normal file
208
vendor/github.com/gin-contrib/cors/cors.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
package cors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Config represents all available options for the middleware.
|
||||
type Config struct {
|
||||
AllowAllOrigins bool
|
||||
|
||||
// AllowOrigins is a list of origins a cross-domain request can be executed from.
|
||||
// If the special "*" value is present in the list, all origins will be allowed.
|
||||
// Default value is []
|
||||
AllowOrigins []string
|
||||
|
||||
// AllowOriginFunc is a custom function to validate the origin. It takes the origin
|
||||
// as an argument and returns true if allowed or false otherwise. If this option is
|
||||
// set, the content of AllowOrigins is ignored.
|
||||
AllowOriginFunc func(origin string) bool
|
||||
|
||||
// Same as AllowOriginFunc except also receives the full request context.
|
||||
// This function should use the context as a read only source and not
|
||||
// have any side effects on the request, such as aborting or injecting
|
||||
// values on the request.
|
||||
AllowOriginWithContextFunc func(c *gin.Context, origin string) bool
|
||||
|
||||
// AllowMethods is a list of methods the client is allowed to use with
|
||||
// cross-domain requests. Default value is simple methods (GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS)
|
||||
AllowMethods []string
|
||||
|
||||
// AllowPrivateNetwork indicates whether the response should include allow private network header
|
||||
AllowPrivateNetwork bool
|
||||
|
||||
// AllowHeaders is list of non simple headers the client is allowed to use with
|
||||
// cross-domain requests.
|
||||
AllowHeaders []string
|
||||
|
||||
// AllowCredentials indicates whether the request can include user credentials like
|
||||
// cookies, HTTP authentication or client side SSL certificates.
|
||||
AllowCredentials bool
|
||||
|
||||
// ExposeHeaders indicates which headers are safe to expose to the API of a CORS
|
||||
// API specification
|
||||
ExposeHeaders []string
|
||||
|
||||
// MaxAge indicates how long (with second-precision) the results of a preflight request
|
||||
// can be cached
|
||||
MaxAge time.Duration
|
||||
|
||||
// Allows to add origins like http://some-domain/*, https://api.* or http://some.*.subdomain.com
|
||||
AllowWildcard bool
|
||||
|
||||
// Allows usage of popular browser extensions schemas
|
||||
AllowBrowserExtensions bool
|
||||
|
||||
// Allows to add custom schema like tauri://
|
||||
CustomSchemas []string
|
||||
|
||||
// Allows usage of WebSocket protocol
|
||||
AllowWebSockets bool
|
||||
|
||||
// Allows usage of file:// schema (dangerous!) use it only when you 100% sure it's needed
|
||||
AllowFiles bool
|
||||
|
||||
// Allows to pass custom OPTIONS response status code for old browsers / clients
|
||||
OptionsResponseStatusCode int
|
||||
}
|
||||
|
||||
// AddAllowMethods is allowed to add custom methods
|
||||
func (c *Config) AddAllowMethods(methods ...string) {
|
||||
c.AllowMethods = append(c.AllowMethods, methods...)
|
||||
}
|
||||
|
||||
// AddAllowHeaders is allowed to add custom headers
|
||||
func (c *Config) AddAllowHeaders(headers ...string) {
|
||||
c.AllowHeaders = append(c.AllowHeaders, headers...)
|
||||
}
|
||||
|
||||
// AddExposeHeaders is allowed to add custom expose headers
|
||||
func (c *Config) AddExposeHeaders(headers ...string) {
|
||||
c.ExposeHeaders = append(c.ExposeHeaders, headers...)
|
||||
}
|
||||
|
||||
func (c Config) getAllowedSchemas() []string {
|
||||
allowedSchemas := DefaultSchemas
|
||||
if c.AllowBrowserExtensions {
|
||||
allowedSchemas = append(allowedSchemas, ExtensionSchemas...)
|
||||
}
|
||||
if c.AllowWebSockets {
|
||||
allowedSchemas = append(allowedSchemas, WebSocketSchemas...)
|
||||
}
|
||||
if c.AllowFiles {
|
||||
allowedSchemas = append(allowedSchemas, FileSchemas...)
|
||||
}
|
||||
if c.CustomSchemas != nil {
|
||||
allowedSchemas = append(allowedSchemas, c.CustomSchemas...)
|
||||
}
|
||||
return allowedSchemas
|
||||
}
|
||||
|
||||
var regexpBasedOrigin = regexp.MustCompile(`^\/(.+)\/[gimuy]?$`)
|
||||
|
||||
func (c Config) validateAllowedSchemas(origin string) bool {
|
||||
allowedSchemas := c.getAllowedSchemas()
|
||||
|
||||
if regexpBasedOrigin.MatchString(origin) {
|
||||
// Normalize regexp-based origins
|
||||
origin = regexpBasedOrigin.FindStringSubmatch(origin)[1]
|
||||
origin = strings.Replace(origin, "?", "", 1)
|
||||
}
|
||||
|
||||
for _, schema := range allowedSchemas {
|
||||
if strings.HasPrefix(origin, schema) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Validate is check configuration of user defined.
|
||||
func (c Config) Validate() error {
|
||||
hasOriginFn := c.AllowOriginFunc != nil
|
||||
hasOriginFn = hasOriginFn || c.AllowOriginWithContextFunc != nil
|
||||
|
||||
if c.AllowAllOrigins && (hasOriginFn || len(c.AllowOrigins) > 0) {
|
||||
originFields := strings.Join([]string{
|
||||
"AllowOriginFunc",
|
||||
"AllowOriginFuncWithContext",
|
||||
"AllowOrigins",
|
||||
}, " or ")
|
||||
return fmt.Errorf(
|
||||
"conflict settings: all origins enabled. %s is not needed",
|
||||
originFields,
|
||||
)
|
||||
}
|
||||
if !c.AllowAllOrigins && !hasOriginFn && len(c.AllowOrigins) == 0 {
|
||||
return errors.New("conflict settings: all origins disabled")
|
||||
}
|
||||
for _, origin := range c.AllowOrigins {
|
||||
if !strings.Contains(origin, "*") && !c.validateAllowedSchemas(origin) {
|
||||
return errors.New("bad origin: origins must contain '*' or include " + strings.Join(c.getAllowedSchemas(), ","))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Config) parseWildcardRules() [][]string {
|
||||
var wRules [][]string
|
||||
|
||||
if !c.AllowWildcard {
|
||||
return wRules
|
||||
}
|
||||
|
||||
for _, o := range c.AllowOrigins {
|
||||
if !strings.Contains(o, "*") {
|
||||
continue
|
||||
}
|
||||
|
||||
if c := strings.Count(o, "*"); c > 1 {
|
||||
panic(errors.New("only one * is allowed").Error())
|
||||
}
|
||||
|
||||
i := strings.Index(o, "*")
|
||||
if i == 0 {
|
||||
wRules = append(wRules, []string{"*", o[1:]})
|
||||
continue
|
||||
}
|
||||
if i == (len(o) - 1) {
|
||||
wRules = append(wRules, []string{o[:i], "*"})
|
||||
continue
|
||||
}
|
||||
|
||||
wRules = append(wRules, []string{o[:i], o[i+1:]})
|
||||
}
|
||||
|
||||
return wRules
|
||||
}
|
||||
|
||||
// DefaultConfig returns a generic default configuration mapped to localhost.
|
||||
func DefaultConfig() Config {
|
||||
return Config{
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"},
|
||||
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type"},
|
||||
AllowCredentials: false,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}
|
||||
}
|
||||
|
||||
// Default returns the location middleware with default configuration.
|
||||
func Default() gin.HandlerFunc {
|
||||
config := DefaultConfig()
|
||||
config.AllowAllOrigins = true
|
||||
return New(config)
|
||||
}
|
||||
|
||||
// New returns the location middleware with user-defined custom configuration.
|
||||
func New(config Config) gin.HandlerFunc {
|
||||
cors := newCors(config)
|
||||
return func(c *gin.Context) {
|
||||
cors.applyCors(c)
|
||||
}
|
||||
}
|
||||
90
vendor/github.com/gin-contrib/cors/utils.go
generated
vendored
Normal file
90
vendor/github.com/gin-contrib/cors/utils.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package cors
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type converter func(string) string
|
||||
|
||||
func generateNormalHeaders(c Config) http.Header {
|
||||
headers := make(http.Header)
|
||||
if c.AllowCredentials {
|
||||
headers.Set("Access-Control-Allow-Credentials", "true")
|
||||
}
|
||||
if len(c.ExposeHeaders) > 0 {
|
||||
exposeHeaders := convert(normalize(c.ExposeHeaders), http.CanonicalHeaderKey)
|
||||
headers.Set("Access-Control-Expose-Headers", strings.Join(exposeHeaders, ","))
|
||||
}
|
||||
if c.AllowAllOrigins {
|
||||
headers.Set("Access-Control-Allow-Origin", "*")
|
||||
} else {
|
||||
headers.Set("Vary", "Origin")
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func generatePreflightHeaders(c Config) http.Header {
|
||||
headers := make(http.Header)
|
||||
if c.AllowCredentials {
|
||||
headers.Set("Access-Control-Allow-Credentials", "true")
|
||||
}
|
||||
if len(c.AllowMethods) > 0 {
|
||||
allowMethods := convert(normalize(c.AllowMethods), strings.ToUpper)
|
||||
value := strings.Join(allowMethods, ",")
|
||||
headers.Set("Access-Control-Allow-Methods", value)
|
||||
}
|
||||
if len(c.AllowHeaders) > 0 {
|
||||
allowHeaders := convert(normalize(c.AllowHeaders), http.CanonicalHeaderKey)
|
||||
value := strings.Join(allowHeaders, ",")
|
||||
headers.Set("Access-Control-Allow-Headers", value)
|
||||
}
|
||||
if c.MaxAge > time.Duration(0) {
|
||||
value := strconv.FormatInt(int64(c.MaxAge/time.Second), 10)
|
||||
headers.Set("Access-Control-Max-Age", value)
|
||||
}
|
||||
|
||||
if c.AllowPrivateNetwork {
|
||||
headers.Set("Access-Control-Allow-Private-Network", "true")
|
||||
}
|
||||
|
||||
if c.AllowAllOrigins {
|
||||
headers.Set("Access-Control-Allow-Origin", "*")
|
||||
} else {
|
||||
// Always set Vary headers
|
||||
// see https://github.com/rs/cors/issues/10,
|
||||
// https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
|
||||
|
||||
headers.Add("Vary", "Origin")
|
||||
headers.Add("Vary", "Access-Control-Request-Method")
|
||||
headers.Add("Vary", "Access-Control-Request-Headers")
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func normalize(values []string) []string {
|
||||
if values == nil {
|
||||
return nil
|
||||
}
|
||||
distinctMap := make(map[string]bool, len(values))
|
||||
normalized := make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
value = strings.TrimSpace(value)
|
||||
value = strings.ToLower(value)
|
||||
if _, seen := distinctMap[value]; !seen {
|
||||
normalized = append(normalized, value)
|
||||
distinctMap[value] = true
|
||||
}
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
func convert(s []string, c converter) []string {
|
||||
var out []string
|
||||
for _, i := range s {
|
||||
out = append(out, c(i))
|
||||
}
|
||||
return out
|
||||
}
|
||||
50
vendor/github.com/gin-contrib/sse/.golangci.yml
generated
vendored
Normal file
50
vendor/github.com/gin-contrib/sse/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
version: "2"
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- bodyclose
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- exhaustive
|
||||
- gochecknoinits
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- noctx
|
||||
- nolintlint
|
||||
- rowserrcheck
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- whitespace
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
29
vendor/github.com/gin-contrib/sse/.goreleaser.yaml
generated
vendored
Normal file
29
vendor/github.com/gin-contrib/sse/.goreleaser.yaml
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
builds:
|
||||
- # If true, skip the build.
|
||||
# Useful for library projects.
|
||||
# Default is false
|
||||
skip: true
|
||||
|
||||
changelog:
|
||||
use: github
|
||||
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
|
||||
21
vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
Normal file
21
vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 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.
|
||||
60
vendor/github.com/gin-contrib/sse/README.md
generated
vendored
Normal file
60
vendor/github.com/gin-contrib/sse/README.md
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
# Server-Sent Events
|
||||
|
||||
[](https://pkg.go.dev/github.com/gin-contrib/sse)
|
||||
[](https://github.com/gin-contrib/sse/actions/workflows/go.yml)
|
||||
[](https://codecov.io/gh/gin-contrib/sse)
|
||||
[](https://goreportcard.com/report/github.com/gin-contrib/sse)
|
||||
|
||||
Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/).
|
||||
|
||||
- [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/)
|
||||
- [Browser support](http://caniuse.com/#feat=eventsource)
|
||||
|
||||
## Sample code
|
||||
|
||||
```go
|
||||
import "github.com/gin-contrib/sse"
|
||||
|
||||
func httpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
// data can be a primitive like a string, an integer or a float
|
||||
sse.Encode(w, sse.Event{
|
||||
Event: "message",
|
||||
Data: "some data\nmore data",
|
||||
})
|
||||
|
||||
// also a complex type, like a map, a struct or a slice
|
||||
sse.Encode(w, sse.Event{
|
||||
Id: "124",
|
||||
Event: "message",
|
||||
Data: map[string]interface{}{
|
||||
"user": "manu",
|
||||
"date": time.Now().Unix(),
|
||||
"content": "hi!",
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
```sh
|
||||
event: message
|
||||
data: some data\\nmore data
|
||||
|
||||
id: 124
|
||||
event: message
|
||||
data: {"content":"hi!","date":1431540810,"user":"manu"}
|
||||
|
||||
```
|
||||
|
||||
## Content-Type
|
||||
|
||||
```go
|
||||
fmt.Println(sse.ContentType)
|
||||
```
|
||||
|
||||
```sh
|
||||
text/event-stream
|
||||
```
|
||||
|
||||
## Decoding support
|
||||
|
||||
There is a client-side implementation of SSE coming soon.
|
||||
117
vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
Normal file
117
vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
// 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 sse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type decoder struct {
|
||||
events []Event
|
||||
}
|
||||
|
||||
func Decode(r io.Reader) ([]Event, error) {
|
||||
var dec decoder
|
||||
return dec.decode(r)
|
||||
}
|
||||
|
||||
func (d *decoder) dispatchEvent(event Event, data string) {
|
||||
dataLength := len(data)
|
||||
if dataLength > 0 {
|
||||
// If the data buffer's last character is a U+000A LINE FEED (LF) character,
|
||||
// then remove the last character from the data buffer.
|
||||
data = data[:dataLength-1]
|
||||
dataLength--
|
||||
}
|
||||
if dataLength == 0 && event.Event == "" {
|
||||
return
|
||||
}
|
||||
if event.Event == "" {
|
||||
event.Event = "message"
|
||||
}
|
||||
event.Data = data
|
||||
d.events = append(d.events, event)
|
||||
}
|
||||
|
||||
func (d *decoder) decode(r io.Reader) ([]Event, error) {
|
||||
buf, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var currentEvent Event
|
||||
dataBuffer := new(bytes.Buffer)
|
||||
// TODO (and unit tests)
|
||||
// Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair,
|
||||
// a single U+000A LINE FEED (LF) character,
|
||||
// or a single U+000D CARRIAGE RETURN (CR) character.
|
||||
lines := bytes.Split(buf, []byte{'\n'})
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
// If the line is empty (a blank line). Dispatch the event.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
// reset current event and data buffer
|
||||
currentEvent = Event{}
|
||||
dataBuffer.Reset()
|
||||
continue
|
||||
}
|
||||
if line[0] == byte(':') {
|
||||
// If the line starts with a U+003A COLON character (:), ignore the line.
|
||||
continue
|
||||
}
|
||||
|
||||
var field, value []byte
|
||||
colonIndex := bytes.IndexRune(line, ':')
|
||||
if colonIndex != -1 {
|
||||
// If the line contains a U+003A COLON character character (:)
|
||||
// Collect the characters on the line before the first U+003A COLON character (:),
|
||||
// and let field be that string.
|
||||
field = line[:colonIndex]
|
||||
// Collect the characters on the line after the first U+003A COLON character (:),
|
||||
// and let value be that string.
|
||||
value = line[colonIndex+1:]
|
||||
// If value starts with a single U+0020 SPACE character, remove it from value.
|
||||
if len(value) > 0 && value[0] == ' ' {
|
||||
value = value[1:]
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the string is not empty but does not contain a U+003A COLON character character (:)
|
||||
// Use the whole line as the field name, and the empty string as the field value.
|
||||
field = line
|
||||
value = []byte{}
|
||||
}
|
||||
// The steps to process the field given a field name and a field value depend on the field name,
|
||||
// as given in the following list. Field names must be compared literally,
|
||||
// with no case folding performed.
|
||||
switch string(field) {
|
||||
case "event":
|
||||
// Set the event name buffer to field value.
|
||||
currentEvent.Event = string(value)
|
||||
case "id":
|
||||
// Set the event stream's last event ID to the field value.
|
||||
currentEvent.Id = string(value)
|
||||
case "retry":
|
||||
// If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9),
|
||||
// then interpret the field value as an integer in base ten, and set the event stream's
|
||||
// reconnection time to that integer.
|
||||
// Otherwise, ignore the field.
|
||||
currentEvent.Id = string(value)
|
||||
case "data":
|
||||
// Append the field value to the data buffer,
|
||||
dataBuffer.Write(value)
|
||||
// then append a single U+000A LINE FEED (LF) character to the data buffer.
|
||||
dataBuffer.WriteString("\n")
|
||||
default:
|
||||
// Otherwise. The field is ignored.
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Once the end of the file is reached, the user agent must dispatch the event one final time.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
return d.events, nil
|
||||
}
|
||||
120
vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
Normal file
120
vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// 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 sse
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Server-Sent Events
|
||||
// W3C Working Draft 29 October 2009
|
||||
// http://www.w3.org/TR/2009/WD-eventsource-20091029/
|
||||
|
||||
const ContentType = "text/event-stream;charset=utf-8"
|
||||
|
||||
var (
|
||||
contentType = []string{ContentType}
|
||||
noCache = []string{"no-cache"}
|
||||
)
|
||||
|
||||
var fieldReplacer = strings.NewReplacer(
|
||||
"\n", "\\n",
|
||||
"\r", "\\r")
|
||||
|
||||
var dataReplacer = strings.NewReplacer(
|
||||
"\n", "\ndata:",
|
||||
"\r", "\\r")
|
||||
|
||||
type Event struct {
|
||||
Event string
|
||||
Id string
|
||||
Retry uint
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func Encode(writer io.Writer, event Event) error {
|
||||
w := checkWriter(writer)
|
||||
writeId(w, event.Id)
|
||||
writeEvent(w, event.Event)
|
||||
writeRetry(w, event.Retry)
|
||||
return writeData(w, event.Data)
|
||||
}
|
||||
|
||||
func writeId(w stringWriter, id string) {
|
||||
if len(id) > 0 {
|
||||
_, _ = w.WriteString("id:")
|
||||
_, _ = fieldReplacer.WriteString(w, id)
|
||||
_, _ = w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeEvent(w stringWriter, event string) {
|
||||
if len(event) > 0 {
|
||||
_, _ = w.WriteString("event:")
|
||||
_, _ = fieldReplacer.WriteString(w, event)
|
||||
_, _ = w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeRetry(w stringWriter, retry uint) {
|
||||
if retry > 0 {
|
||||
_, _ = w.WriteString("retry:")
|
||||
_, _ = w.WriteString(strconv.FormatUint(uint64(retry), 10))
|
||||
_, _ = w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeData(w stringWriter, data interface{}) error {
|
||||
_, _ = w.WriteString("data:")
|
||||
|
||||
bData, ok := data.([]byte)
|
||||
if ok {
|
||||
_, _ = dataReplacer.WriteString(w, string(bData))
|
||||
_, _ = w.WriteString("\n\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
switch kindOfData(data) { //nolint:exhaustive
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = w.WriteString("\n")
|
||||
default:
|
||||
_, _ = dataReplacer.WriteString(w, fmt.Sprint(data))
|
||||
_, _ = w.WriteString("\n\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r Event) Render(w http.ResponseWriter) error {
|
||||
r.WriteContentType(w)
|
||||
return Encode(w, r)
|
||||
}
|
||||
|
||||
func (r Event) WriteContentType(w http.ResponseWriter) {
|
||||
header := w.Header()
|
||||
header["Content-Type"] = contentType
|
||||
|
||||
if _, exist := header["Cache-Control"]; !exist {
|
||||
header["Cache-Control"] = noCache
|
||||
}
|
||||
}
|
||||
|
||||
func kindOfData(data interface{}) reflect.Kind {
|
||||
value := reflect.ValueOf(data)
|
||||
valueType := value.Kind()
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
return valueType
|
||||
}
|
||||
24
vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
Normal file
24
vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package sse
|
||||
|
||||
import "io"
|
||||
|
||||
type stringWriter interface {
|
||||
io.Writer
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
type stringWrapper struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (w stringWrapper) WriteString(str string) (int, error) {
|
||||
return w.Write([]byte(str))
|
||||
}
|
||||
|
||||
func checkWriter(writer io.Writer) stringWriter {
|
||||
if w, ok := writer.(stringWriter); ok {
|
||||
return w
|
||||
} else {
|
||||
return stringWrapper{writer}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user