Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
** Removed the `maxResponseContentLength` connection option and its `HttpObjectAggregator` cap; responses are streamed and the new `readTimeout` is the partial mitigation.
** Reconciled the `validationRequest` default: the builder default is now `g.inject(0)` to match the `Settings` default (it was previously `''`).
* Added configurable CORS `allowedOrigins` setting to Gremlin Server; warns when wildcard origin is used alongside authentication.
* Standardized `gremlin-go` connection options per the TinkerPop 4.x GLV proposal:
** Moved `BasicAuth`/`SigV4Auth`/`SigV4AuthWithCredentials` out of package `gremlingo` into a new `auth` sub-package as `auth.Basic`/`auth.SigV4`/`auth.SigV4WithCredentials`. The flat `gremlingo` functions have been removed; use the `auth` sub-package.
** Renamed `MaximumConcurrentConnections` to `MaxConnections` (default 128), `IdleConnectionTimeout` to `IdleTimeoutMillis` (default 180000), `KeepAliveInterval` to `KeepAliveTimeMillis` (default 30000), `ConnectionTimeout` to `ConnectTimeoutMillis` (default 5000), `TlsConfig` to `Ssl` (`*tls.Config`), and `RequestInterceptors` to `Interceptors`. Each timeout has a `time.Duration` companion (`IdleTimeout`/`KeepAliveTime`/`ConnectTimeout`); set only one form per option. *(breaking)*
** Renamed `EnableCompression` to `Compression`, now a typed `Compression` const (`CompressionNone`/`CompressionDeflate`) defaulting to `CompressionDeflate` (compression on by default; set `CompressionNone` to disable); `Accept-Encoding: deflate` is sent by default and the manual per-chunk deflate decode path is retained. *(breaking)*
** Added `BatchSize` (default 64), a connection-level default that fills the per-request `batchSize` when unset.
** Added `MaxResponseHeaderBytes`, exposing `http.Transport.MaxResponseHeaderBytes`.
** Added `Proxy` and set `http.Transport.Proxy` to `http.ProxyFromEnvironment` by default, fixing a regression where a custom transport silently dropped environment proxy configuration.
** Added `ReadTimeoutMillis` (with a `time.Duration` companion `ReadTimeout`; set only one), an idle-read timeout reset on each read (via `SetReadDeadline`) that is re-armed across pooled-connection reuse and does not set `http.Client.Timeout`.
** Added `BulkResults` (default false), a connection-level default for `bulkResults` applied to every request unless overridden per-request, aligning gremlin-go with the other GLVs which already expose a connection-level setting; the `DriverRemoteConnection` traversal path defaults to `true` regardless of this setting.
* Fixed `ByteBuf` leak in `GraphBinaryMessageSerializerV4` when serialization throws an `IOException`.
* Changed `Tree` to no longer extend `HashMap`; it is now a final class with a tree-shaped API (`childAt`, `hasChild`, `contains`, `findSubtree`, `getOrCreateChild`, `getNodesAtDepth`, `getLeafNodes`, `nodeCount`) and is no longer a `Map`.
* Changed `count(local)` on a `Tree` to return the total node count (`Tree.nodeCount()`) instead of the root-entry count.
Expand Down
75 changes: 56 additions & 19 deletions docs/src/reference/gremlin-variants.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -189,17 +189,17 @@ headers, or request signing. Plain text and SigV4 authentication are provided as
// Plain text authentication
remote, err := gremlingo.NewDriverRemoteConnection("https://localhost:8182/gremlin",
func(settings *gremlingo.DriverRemoteConnectionSettings) {
settings.TlsConfig = &tls.Config{InsecureSkipVerify: true}
settings.RequestInterceptors = []gremlingo.RequestInterceptor{
gremlingo.BasicAuth("username", "password"),
settings.Ssl = &tls.Config{InsecureSkipVerify: true}
settings.Interceptors = []gremlingo.RequestInterceptor{
auth.Basic("username", "password"),
}
})

// SigV4 authentication
remote, err := gremlingo.NewDriverRemoteConnection("https://localhost:8182/gremlin",
func(settings *gremlingo.DriverRemoteConnectionSettings) {
settings.RequestInterceptors = []gremlingo.RequestInterceptor{
gremlingo.SigV4Auth("service-region", "service-name"),
settings.Interceptors = []gremlingo.RequestInterceptor{
auth.SigV4("service-region", "service-name"),
}
})
----
Expand All @@ -220,8 +220,8 @@ The following options are allowed on a per-request basis in this fashion: `batch
`evaluationTimeout`.

NOTE: When submitting traversals through `DriverRemoteConnection`, `bulkResults` defaults to `true` per-request
to optimize result transfer. This does not apply to direct `Client.Submit()` calls, where `bulkResults` must be
set explicitly if desired.
to optimize result transfer. For direct `Client.Submit()` calls, set the connection-level `BulkResults` option to
apply a default to every request, or set `bulkResults` per-request to override it.

anchor:go-imports[]
[[gremlin-go-imports]]
Expand Down Expand Up @@ -259,21 +259,58 @@ can be passed to the `NewClient` or `NewDriverRemoteConnection` functions as con
|LogVerbosity |Log verbosity.|gremlingo.INFO
|Logger |Instance of logger. |log
|Language |Language used for logging messages. |language.English
|TlsConfig |TLS configuration. |empty
|ConnectionTimeout | Timeout for establishing connection. |15 seconds
|MaximumConcurrentConnections | Maximum number of concurrent TCP connections to the server. |128
|Ssl |TLS configuration. |empty
|ConnectTimeoutMillis | Timeout in milliseconds for establishing the connection (TCP connect plus TLS handshake). Also settable as `ConnectTimeout` (a `time.Duration`); set only one. |5000
|MaxConnections | Maximum number of concurrent TCP connections to the server. |128
|MaxIdleConnections | Maximum number of idle (keep-alive) connections in the pool. |8
|IdleConnectionTimeout | How long idle connections remain in the pool before being closed. |180 seconds
|KeepAliveInterval | TCP keep-alive probe interval. |30 seconds
|EnableCompression |Flag to enable compression. |false
|IdleTimeoutMillis | How long in milliseconds idle connections remain in the pool before being closed. Also settable as `IdleTimeout` (a `time.Duration`); set only one. |180000
|KeepAliveTimeMillis | Idle time in milliseconds before TCP keep-alive probes begin. Also settable as `KeepAliveTime` (a `time.Duration`); set only one. |30000
|ReadTimeoutMillis | Idle-read timeout in milliseconds reset on each read of the response body. Set to `0` to disable. Also settable as `ReadTimeout` (a `time.Duration`); set only one. |0
|Compression |The wire compression negotiated with the server (`gremlingo.CompressionNone` or `gremlingo.CompressionDeflate`). |gremlingo.CompressionDeflate
|BatchSize |The connection-level default batch size used when a request does not specify one. |64
|BulkResults |Connection-level default for `bulkResults`, applied to every request unless overridden per-request. The `DriverRemoteConnection` traversal path defaults to `true` regardless of this setting. |false
|MaxResponseHeaderBytes |Limit on the number of response header bytes the client will read. Maps to `http.Transport.MaxResponseHeaderBytes`. |0 (net/http default)
|Proxy |Function returning the proxy URL to use for a request. When `nil`, uses `http.ProxyFromEnvironment`. |nil
|EnableUserAgentOnConnect |Enables sending a user agent to the server during connection requests.
More details can be found in provider docs
link:https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_graph_driver_provider_requirements[here].|true
|RequestInterceptors |Functions that modify HTTP requests before sending. Used for authentication and custom headers. |empty
|Interceptors |Functions that modify HTTP requests before sending. Used for authentication and custom headers. |empty
|PDTRegistry |A `*PDTRegistry` for hydrating and dehydrating <<gremlin-go-pdt,Provider Defined Types>>. |`nil`
|Auth |A single RequestInterceptor for authentication (e.g. `BasicAuth`). Always appended to the end of the interceptor list so it runs last. |nil
|Auth |A single RequestInterceptor for authentication (e.g. `auth.Basic`). Always appended to the end of the interceptor list so it runs last. |nil
|=========================================================

Note that no driver timeout bounds the *total* duration of a request once it is under way. `ReadTimeout` only bounds
the gap between response chunks, so a response that keeps producing chunks will not time out no matter how long it
runs overall, and there is no client-side "overall" request timeout. If you need an absolute deadline, impose it in
your application around the call. Because `Submit` does not accept a `context.Context`, run it in a goroutine and
bound it with a `select`:

[source,go]
----
// bound the entire request (submit plus full result iteration) to 30 seconds
type outcome struct {
results []*gremlingo.Result
err error
}
done := make(chan outcome, 1)
go func() {
rs, err := client.Submit("g.V().out().out()")
if err != nil {
done <- outcome{nil, err}
return
}
results, err := rs.All()
done <- outcome{results, err}
}()

select {
case o := <-done:
// use o.results / o.err
case <-time.After(30 * time.Second):
// deadline exceeded; stop waiting on the request
}
----

[[gremlin-go-interceptors]]
=== RequestInterceptor

Expand All @@ -284,17 +321,17 @@ servers without having to use interceptors. This is intended for cases where the

A `RequestInterceptor` is a function with the signature `func(*HttpRequest) error` that mutates the `HttpRequest`
in place. A slice of these is maintained and will be run sequentially for each request. When creating a
`DriverRemoteConnection` or `Client`, the `RequestInterceptors` field on the settings struct accepts an ordered
`DriverRemoteConnection` or `Client`, the `Interceptors` field on the settings struct accepts an ordered
slice of interceptors. Order matters, so if one interceptor depends on another's output, ensure they are added in
the correct order. Note that authentication (e.g. `BasicAuth`, `SigV4Auth`) is also implemented using interceptors.
the correct order. Note that authentication (e.g. `auth.Basic`, `auth.SigV4`) is also implemented using interceptors.
The `auth` convenience on connection settings appends the auth interceptor to the end of the list so it runs last.

[source,go]
----
remote, err := gremlingo.NewDriverRemoteConnection("http://localhost:8182/gremlin",
func(settings *gremlingo.DriverRemoteConnectionSettings) {
settings.RequestInterceptors = []gremlingo.RequestInterceptor{
gremlingo.BasicAuth("username", "password"),
settings.Interceptors = []gremlingo.RequestInterceptor{
auth.Basic("username", "password"),
func(req *gremlingo.HttpRequest) error {
req.Headers.Set("X-Custom-Header", "value")
return nil
Expand Down
45 changes: 45 additions & 0 deletions docs/src/upgrade/release-4.x.x.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,51 @@ complete list of all the modifications that are part of this release.

=== Upgrading for Users

==== Standardizing Go Connection Options

TinkerPop 4.x standardizes connection option names and defaults across the GLVs. In `gremlin-go`, several
`DriverRemoteConnectionSettings`/`ClientSettings` options introduced for the HTTP driver in 4.0.0-beta.2 have been
renamed for consistency, the authentication helpers have moved into a dedicated `auth` sub-package, and a number of
new options have been added. The notes below describe the Go changes. See <<glv-driver-changes, GLV Driver Changes>>
for the equivalent changes in the other drivers.

Renames (breaking). The following settings fields have been renamed. Because they are struct fields, they cannot be
aliased, so existing code must be updated to the new names:

- `MaximumConcurrentConnections` is now `MaxConnections` (default 128).
- `IdleConnectionTimeout` is now `IdleTimeoutMillis` (default 180000), an `int` of milliseconds. The `time.Duration` companion `IdleTimeout` may be set instead (set only one).
- `KeepAliveInterval` is now `KeepAliveTimeMillis` (default 30000), an `int` of milliseconds. The `time.Duration` companion `KeepAliveTime` may be set instead (set only one).
- `ConnectionTimeout` is now `ConnectTimeoutMillis` (default 5000), an `int` of milliseconds. The `time.Duration` companion `ConnectTimeout` may be set instead (set only one).
- `TlsConfig` (`*tls.Config`) is now `Ssl`.
- `RequestInterceptors` is now `Interceptors`.
- `EnableCompression` is now `Compression`.
- The `BasicAuth`, `SigV4Auth`, and `SigV4AuthWithCredentials` functions have moved out of package `gremlingo` into a
new `auth` sub-package (`github.com/apache/tinkerpop/gremlin-go/v4/driver/auth`) as `auth.Basic`, `auth.SigV4`, and
`auth.SigV4WithCredentials`. The flat `gremlingo` functions have been removed; use the `auth` sub-package.

Behavior changes. These change runtime behavior on upgrade, even if you do not change your configuration:

- `Compression` is now a typed `Compression` const (`gremlingo.CompressionNone`/`gremlingo.CompressionDeflate`)
defaulting to `CompressionDeflate` (compression on by default), so the driver sends `Accept-Encoding: deflate` by
default. Set `gremlingo.CompressionNone` to disable it. The manual per-chunk deflate decode path is retained.
- `http.Transport.Proxy` now defaults to `http.ProxyFromEnvironment`, so the standard `HTTP_PROXY`/`HTTPS_PROXY`/
`NO_PROXY` environment variables are honored. Previously the custom transport left `Proxy` unset, silently dropping
any environment proxy configuration.

New options:

- `ReadTimeoutMillis` (default 0, disabled), an `int` of milliseconds: a per-read idle timeout reset on each read of
the response body and re-armed across pooled-connection reuse, so it never fires while a pooled connection is idle
between requests. The `time.Duration` companion `ReadTimeout` may be set instead (set only one).
- `MaxResponseHeaderBytes`: exposes `http.Transport.MaxResponseHeaderBytes` (native bytes).
- `Proxy`: an explicit `func(*http.Request) (*url.URL, error)` proxy override for the transport.
- `BatchSize` (default 64): a connection-level default that fills a request's `batchSize` when it is left
unset.
- `BulkResults` (default false): a connection-level default for `bulkResults` applied to every request unless
overridden per-request. The `DriverRemoteConnection` traversal path defaults to `true` regardless of this setting.

See: link:https://lists.apache.org/thread/yqtr2wnb1kq2pqqq4002cz511q5o0bkg[[DISCUSS] Standardizing GLV connection options in TinkerPop 4].

==== Standardizing Python Connection Options

TinkerPop 4.x standardizes connection option names and defaults across the GLVs. In `gremlin-python`, several
Expand Down
27 changes: 16 additions & 11 deletions gremlin-go/driver/auth.go → gremlin-go/driver/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ specific language governing permissions and limitations
under the License.
*/

package gremlingo
// Package auth provides authentication interceptors for the gremlin-go driver.
// Each constructor returns a gremlingo.RequestInterceptor that can be assigned to
// the Auth field of ClientSettings or DriverRemoteConnectionSettings.
package auth

import (
"context"
Expand All @@ -29,30 +32,32 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/config"

gremlingo "github.com/apache/tinkerpop/gremlin-go/v4/driver"
)

// BasicAuth returns a RequestInterceptor that adds Basic authentication header.
func BasicAuth(username, password string) RequestInterceptor {
// Basic returns a RequestInterceptor that adds a Basic authentication header.
func Basic(username, password string) gremlingo.RequestInterceptor {
encoded := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
return func(req *HttpRequest) error {
req.Headers.Set(HeaderAuthorization, "Basic "+encoded)
return func(req *gremlingo.HttpRequest) error {
req.Headers.Set(gremlingo.HeaderAuthorization, "Basic "+encoded)
return nil
}
}

// SigV4Auth returns a RequestInterceptor that signs requests using AWS SigV4.
// SigV4 returns a RequestInterceptor that signs requests using AWS SigV4.
// It uses the default AWS credential chain (env vars, shared config, IAM role, etc.)
func SigV4Auth(region, service string) RequestInterceptor {
return SigV4AuthWithCredentials(region, service, nil)
func SigV4(region, service string) gremlingo.RequestInterceptor {
return SigV4WithCredentials(region, service, nil)
}

// SigV4AuthWithCredentials returns a RequestInterceptor that signs requests using AWS SigV4
// SigV4WithCredentials returns a RequestInterceptor that signs requests using AWS SigV4
// with the provided credentials provider. If provider is nil, uses default credential chain.
// If the request body has not been serialized yet (*RequestMessage), it is automatically
// serialized to JSON before signing via SerializeBody().
//
// Caches the signer and credentials provider for efficiency.
func SigV4AuthWithCredentials(region, service string, credentialsProvider aws.CredentialsProvider) RequestInterceptor {
func SigV4WithCredentials(region, service string, credentialsProvider aws.CredentialsProvider) gremlingo.RequestInterceptor {
// Create signer once - it's stateless and safe to reuse
signer := v4.NewSigner()

Expand All @@ -61,7 +66,7 @@ func SigV4AuthWithCredentials(region, service string, credentialsProvider aws.Cr
var providerOnce sync.Once
var providerErr error

return func(req *HttpRequest) error {
return func(req *gremlingo.HttpRequest) error {
// Ensure body is serialized to JSON bytes before signing.
// SerializeBody is idempotent: safe to call even if already serialized.
if _, err := req.SerializeBody(); err != nil {
Expand Down
Loading
Loading