Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0c154b8
add new transport
giortzisg Sep 24, 2025
fc93d2c
fix lint
giortzisg Sep 25, 2025
3c7498e
fix tests
giortzisg Sep 25, 2025
0a406ba
modify envelope serialization and tests
giortzisg Sep 26, 2025
6f9c638
change transport opts
giortzisg Sep 26, 2025
bf26d59
remove transport.Configure
giortzisg Sep 26, 2025
c7205ca
add proper await on queue flush
giortzisg Sep 26, 2025
8c8a4bd
add test for marshall fallback
giortzisg Sep 29, 2025
4228142
fix tests
giortzisg Sep 29, 2025
803349d
add sendEvent
giortzisg Sep 29, 2025
51f0373
fix dsn exporting
giortzisg Sep 30, 2025
58a7b02
enhance transport test suite
giortzisg Sep 30, 2025
1ed184b
change backpressure test
giortzisg Sep 30, 2025
7a2f452
Merge branch 'master' into feat/transport-envelope
giortzisg Oct 6, 2025
a146a1e
specify min tls version
giortzisg Oct 6, 2025
871ade0
use global debuglog
giortzisg Oct 6, 2025
4c15f3a
chore: amend debug output and func comments
giortzisg Oct 8, 2025
b2c7dc4
chore: refactor tests
giortzisg Oct 8, 2025
9d368d4
chore: fix overflow test
giortzisg Oct 8, 2025
a357417
add noopTransport
giortzisg Oct 9, 2025
992feaf
add internalTransport wrapper
giortzisg Oct 9, 2025
bc5d4b8
chore: make internalTransportAdapter private
giortzisg Oct 9, 2025
f89d05d
chore: fix race
giortzisg Oct 9, 2025
ec10979
chore: reexport internal wrapper
giortzisg Oct 9, 2025
17d1a15
change RequestHeaders receiver
giortzisg Oct 9, 2025
d206afe
modify internal transport adapters
giortzisg Oct 9, 2025
d61df59
Merge branch 'feat/transport-buffers' into feat/transport-envelope
giortzisg Oct 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 12 additions & 208 deletions dsn.go
Original file line number Diff line number Diff line change
@@ -1,233 +1,37 @@
package sentry

import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"time"
"github.com/getsentry/sentry-go/internal/protocol"
)

type scheme string
// Re-export protocol types to maintain public API compatibility

const (
schemeHTTP scheme = "http"
schemeHTTPS scheme = "https"
)

func (scheme scheme) defaultPort() int {
switch scheme {
case schemeHTTPS:
return 443
case schemeHTTP:
return 80
default:
return 80
}
// Dsn is used as the remote address source to client transport.
type Dsn struct {
protocol.Dsn
}

// DsnParseError represents an error that occurs if a Sentry
// DSN cannot be parsed.
type DsnParseError struct {
Message string
}

func (e DsnParseError) Error() string {
return "[Sentry] DsnParseError: " + e.Message
}

// Dsn is used as the remote address source to client transport.
type Dsn struct {
scheme scheme
publicKey string
secretKey string
host string
port int
path string
projectID string
}
type DsnParseError = protocol.DsnParseError

// NewDsn creates a Dsn by parsing rawURL. Most users will never call this
// function directly. It is provided for use in custom Transport
// implementations.
func NewDsn(rawURL string) (*Dsn, error) {
// Parse
parsedURL, err := url.Parse(rawURL)
protocolDsn, err := protocol.NewDsn(rawURL)
if err != nil {
return nil, &DsnParseError{fmt.Sprintf("invalid url: %v", err)}
}

// Scheme
var scheme scheme
switch parsedURL.Scheme {
case "http":
scheme = schemeHTTP
case "https":
scheme = schemeHTTPS
default:
return nil, &DsnParseError{"invalid scheme"}
}

// PublicKey
publicKey := parsedURL.User.Username()
if publicKey == "" {
return nil, &DsnParseError{"empty username"}
}

// SecretKey
var secretKey string
if parsedSecretKey, ok := parsedURL.User.Password(); ok {
secretKey = parsedSecretKey
}

// Host
host := parsedURL.Hostname()
if host == "" {
return nil, &DsnParseError{"empty host"}
}

// Port
var port int
if p := parsedURL.Port(); p != "" {
port, err = strconv.Atoi(p)
if err != nil {
return nil, &DsnParseError{"invalid port"}
}
} else {
port = scheme.defaultPort()
}

// ProjectID
if parsedURL.Path == "" || parsedURL.Path == "/" {
return nil, &DsnParseError{"empty project id"}
}
pathSegments := strings.Split(parsedURL.Path[1:], "/")
projectID := pathSegments[len(pathSegments)-1]

if projectID == "" {
return nil, &DsnParseError{"empty project id"}
}

// Path
var path string
if len(pathSegments) > 1 {
path = "/" + strings.Join(pathSegments[0:len(pathSegments)-1], "/")
}

return &Dsn{
scheme: scheme,
publicKey: publicKey,
secretKey: secretKey,
host: host,
port: port,
path: path,
projectID: projectID,
}, nil
}

// String formats Dsn struct into a valid string url.
func (dsn Dsn) String() string {
var url string
url += fmt.Sprintf("%s://%s", dsn.scheme, dsn.publicKey)
if dsn.secretKey != "" {
url += fmt.Sprintf(":%s", dsn.secretKey)
}
url += fmt.Sprintf("@%s", dsn.host)
if dsn.port != dsn.scheme.defaultPort() {
url += fmt.Sprintf(":%d", dsn.port)
return nil, err
}
if dsn.path != "" {
url += dsn.path
}
url += fmt.Sprintf("/%s", dsn.projectID)
return url
}

// Get the scheme of the DSN.
func (dsn Dsn) GetScheme() string {
return string(dsn.scheme)
}

// Get the public key of the DSN.
func (dsn Dsn) GetPublicKey() string {
return dsn.publicKey
}

// Get the secret key of the DSN.
func (dsn Dsn) GetSecretKey() string {
return dsn.secretKey
}

// Get the host of the DSN.
func (dsn Dsn) GetHost() string {
return dsn.host
}

// Get the port of the DSN.
func (dsn Dsn) GetPort() int {
return dsn.port
}

// Get the path of the DSN.
func (dsn Dsn) GetPath() string {
return dsn.path
return &Dsn{Dsn: *protocolDsn}, nil
}

// Get the project ID of the DSN.
func (dsn Dsn) GetProjectID() string {
return dsn.projectID
}

// GetAPIURL returns the URL of the envelope endpoint of the project
// associated with the DSN.
func (dsn Dsn) GetAPIURL() *url.URL {
var rawURL string
rawURL += fmt.Sprintf("%s://%s", dsn.scheme, dsn.host)
if dsn.port != dsn.scheme.defaultPort() {
rawURL += fmt.Sprintf(":%d", dsn.port)
}
if dsn.path != "" {
rawURL += dsn.path
}
rawURL += fmt.Sprintf("/api/%s/%s/", dsn.projectID, "envelope")
parsedURL, _ := url.Parse(rawURL)
return parsedURL
}

// RequestHeaders returns all the necessary headers that have to be used in the transport when seinding events
// RequestHeaders returns all the necessary headers that have to be used in the transport when sending events
// to the /store endpoint.
//
// Deprecated: This method shall only be used if you want to implement your own transport that sends events to
// the /store endpoint. If you're using the transport provided by the SDK, all necessary headers to authenticate
// against the /envelope endpoint are added automatically.
func (dsn Dsn) RequestHeaders() map[string]string {
auth := fmt.Sprintf("Sentry sentry_version=%s, sentry_timestamp=%d, "+
"sentry_client=sentry.go/%s, sentry_key=%s", apiVersion, time.Now().Unix(), SDKVersion, dsn.publicKey)

if dsn.secretKey != "" {
auth = fmt.Sprintf("%s, sentry_secret=%s", auth, dsn.secretKey)
}

return map[string]string{
"Content-Type": "application/json",
"X-Sentry-Auth": auth,
}
}

// MarshalJSON converts the Dsn struct to JSON.
func (dsn Dsn) MarshalJSON() ([]byte, error) {
return json.Marshal(dsn.String())
}

// UnmarshalJSON converts JSON data to the Dsn struct.
func (dsn *Dsn) UnmarshalJSON(data []byte) error {
var str string
_ = json.Unmarshal(data, &str)
newDsn, err := NewDsn(str)
if err != nil {
return err
}
*dsn = *newDsn
return nil
func (dsn *Dsn) RequestHeaders() map[string]string {
return dsn.Dsn.RequestHeaders(SDKVersion)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing SDKVersion Causes Compilation Error

The sentry.Dsn.RequestHeaders method calls protocol.Dsn.RequestHeaders(SDKVersion), but SDKVersion is not defined in sentry/dsn.go, causing a compilation error. This dependency on SDKVersion is new, as the protocol.Dsn.RequestHeaders method now requires this parameter.

Additional Locations (1)

Fix in Cursor Fix in Web

}
Loading
Loading