httpclient

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package httpclient builds an *http.Client tuned for an SAP BTP Destination Service entry. It is the foundation of M3 (HTTP destination support).

Three things the client takes care of automatically:

  • Authorization: tokens delivered alongside the destination by the BTP Destination Service (dest.AuthTokens) are attached to outgoing requests using each token's prepared HTTPHeader (Type "Bearer", value, etc.). If the destination has no AuthTokens, no auth header is set; the caller may add their own.

  • On-prem routing: when ProxyType=OnPremise and a connectivity.Dialer is supplied, the client's transport DialContext is replaced so every TCP open goes through the SAP Cloud Connector tunnel. The plain Go http.Transport then negotiates TLS over the dialed conn — meaning https:// destinations behind Cloud Connector work without further configuration.

  • Cookie jar: a per-client cookie jar is enabled by default so OData v2 services that bind a session cookie to the X-CSRF-Token can be used for writes (see FetchCSRF).

Basic usage:

dest, _ := destClient.Find(ctx, "MY_HTTP_DEST")
client, baseURL, err := httpclient.New(dest, httpclient.Config{
    Dialer: connDialer, // nil for Internet destinations
})
resp, err := client.Get(baseURL + "/sap/opu/odata/.../EntitySet?$top=10")

OData v2 write flow:

csrf, err := httpclient.FetchCSRF(ctx, client, baseURL+"/")
req, _ := http.NewRequestWithContext(ctx, "POST", baseURL+"/Items", body)
req.Header.Set("X-CSRF-Token", csrf)
req.Header.Set("Content-Type", "application/json")
resp, _ := client.Do(req)

The package depends only on the sibling btp-go modules and the standard library.

Example

Example shows the standard use: resolve a destination, build a client, call an OData service.

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/bluefunda/btp-go/connectivity"
	"github.com/bluefunda/btp-go/destination"
	"github.com/bluefunda/btp-go/httpclient"
)

func main() {
	// Resolved destination from the BTP Destination Service. In real code
	// you'd call destination.Client.Find(ctx, "MY_HTTP_DEST").
	var dest *destination.Destination

	// Connectivity dialer for OnPremise destinations. nil for Internet.
	var dialer *connectivity.Dialer

	client, baseURL, err := httpclient.New(dest, httpclient.Config{
		Dialer:       dialer,
		Timeout:      15 * time.Second,
		ExtraHeaders: http.Header{"Accept": []string{"application/json"}},
	})
	if err != nil {
		log.Fatal(err)
	}

	resp, err := client.Get(baseURL + "/sap/opu/odata/sap/MY_SERVICE/Items?$top=5&$format=json")
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	var payload struct {
		D struct {
			Results []map[string]any `json:"results"`
		} `json:"d"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("got %d items\n", len(payload.D.Results))
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrNoURL = errors.New("httpclient: destination has no URL")

ErrNoURL indicates the destination has no usable URL field.

Functions

func FetchCSRF

func FetchCSRF(ctx context.Context, client *http.Client, fetchURL string) (string, error)

FetchCSRF performs a GET against fetchURL with X-CSRF-Token: Fetch and returns the X-CSRF-Token header from the response, suitable for use in subsequent OData v2 write requests on the same client (which carries any set-cookie session state via its jar).

fetchURL is typically the destination's service-document URL, e.g. "<base>/sap/opu/odata/sap/MY_SERVICE/" — many SAP OData services accept a Fetch request against any safe URL on the service path.

Example

ExampleFetchCSRF shows the OData v2 write flow: fetch a CSRF token, then submit a POST that carries the token + the cookie jar's session.

package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/bluefunda/btp-go/httpclient"
)

func main() {
	var client *http.Client
	var baseURL string

	csrf, err := httpclient.FetchCSRF(context.Background(), client, baseURL+"/sap/opu/odata/sap/MY_SERVICE/")
	if err != nil {
		log.Fatal(err)
	}

	body := io.NopCloser(nil) // your serialised payload
	req, _ := http.NewRequestWithContext(context.Background(), http.MethodPost, baseURL+"/Items", body)
	req.Header.Set("X-CSRF-Token", csrf)
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	fmt.Println("created:", resp.Status)
}

func New

func New(dest *destination.Destination, cfg Config) (*http.Client, string, error)

New returns an *http.Client and the destination's base URL configured according to dest + cfg. Per-request paths should be appended to the returned base URL by the caller.

dest.AuthTokens (the per-token HTTPHeader prepared by the BTP Destination Service) is attached to outgoing requests via a wrapping RoundTripper. When dest has no AuthTokens, the client sends no auth header.

Types

type Config

type Config struct {
	// Dialer is the SAP Cloud Connector connectivity dialer (SOCKS5).
	// When non-nil AND the destination's ProxyType is "OnPremise", the
	// client's transport routes every TCP open through the connectivity
	// tunnel as raw TCP — matching SCC TCP rules.
	//
	// For HTTP destinations whose SCC row is Protocol=HTTP, prefer the
	// HTTPProxy field below — when both are set, HTTPProxy wins.
	// *connectivity.Dialer satisfies this interface automatically.
	Dialer Dialer

	// HTTPProxy routes via the connectivity proxy's HTTP CONNECT mode
	// instead of SOCKS5. Use for HTTP destinations on CF where SCC has
	// HTTP-protocol rules. When non-nil, Dialer is ignored.
	HTTPProxy *HTTPProxyConfig

	// TLSConfig optionally overrides the default TLS configuration used
	// by the underlying http.Transport. The zero value uses Go defaults
	// (system root CAs, hostname verification on).
	TLSConfig *tls.Config

	// Timeout is the per-request timeout assigned to the returned
	// *http.Client. Zero defaults to 30s. Set explicitly to disable
	// (use http.Client.Timeout = 0).
	Timeout time.Duration

	// DisableCookieJar suppresses the default cookie jar. Set when the
	// caller manages cookies elsewhere or doesn't want session affinity.
	DisableCookieJar bool

	// ExtraHeaders are applied to every outgoing request after the
	// destination's auth headers. Useful for static headers like
	// "Accept: application/json" or "x-api-key" overrides.
	ExtraHeaders http.Header
}

Config tunes the client returned by New.

type Dialer

type Dialer interface {
	Dial(ctx context.Context, host string, port uint16, locationID string) (net.Conn, error)
}

Dialer establishes a proxied TCP connection through the SAP BTP Connectivity Service SOCKS5 tunnel. *connectivity.Dialer satisfies this interface automatically.

type HTTPProxyConfig

type HTTPProxyConfig struct {
	// ProxyHost is the connectivity proxy hostname.
	ProxyHost string

	// ProxyPort is the proxy's HTTP port (typically 20003 on CF).
	ProxyPort string

	// TokenSource issues the XSUAA JWT used for Proxy-Authorization on
	// every outgoing request and on CONNECT preambles for HTTPS targets.
	TokenSource TokenSource

	// LocationID is the Cloud Connector location ID to route through.
	// Empty selects the subaccount's default location.
	LocationID string
}

HTTPProxyConfig routes the client's transport through the SAP BTP Connectivity Service's HTTP CONNECT proxy (typically connectivityproxy.internal:20003). The Cloud Connector matches HTTP rules against requests received via this path; SOCKS5 traffic on the same proxy matches TCP rules instead. Use this for HTTP/HTTPS destinations whose SCC row is configured Protocol=HTTP.

type TokenSource

type TokenSource interface {
	Token(ctx context.Context) (string, error)
}

TokenSource mints XSUAA bearer JWTs for proxy auth. Defined locally so the package depends only on stdlib + sibling btp-go modules; xsuaa's client-credentials source satisfies it via its Token(ctx) method.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL