gateway.go 2.8 KB
Newer Older
Brian Tiger Chow's avatar
Brian Tiger Chow committed
1 2 3
package corehttp

import (
Jeromy's avatar
Jeromy committed
4
	"fmt"
5
	"net"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
6
	"net/http"
Steven Allen's avatar
Steven Allen committed
7
	"sort"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
8

tavit ohanian's avatar
tavit ohanian committed
9 10 11
	version "gitlab.dms3.io/dms3/go-dms3"
	core "gitlab.dms3.io/dms3/go-dms3/core"
	coreapi "gitlab.dms3.io/dms3/go-dms3/core/coreapi"
Jan Winkelmann's avatar
Jan Winkelmann committed
12

tavit ohanian's avatar
tavit ohanian committed
13 14
	options "gitlab.dms3.io/dms3/interface-go-dms3-core/options"
	id "gitlab.dms3.io/p2p/go-p2p/p2p/protocol/identify"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
15 16
)

17
type GatewayConfig struct {
18 19 20
	Headers      map[string][]string
	Writable     bool
	PathPrefixes []string
21 22
}

Steven Allen's avatar
Steven Allen committed
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
// A helper function to clean up a set of headers:
// 1. Canonicalizes.
// 2. Deduplicates.
// 3. Sorts.
func cleanHeaderSet(headers []string) []string {
	// Deduplicate and canonicalize.
	m := make(map[string]struct{}, len(headers))
	for _, h := range headers {
		m[http.CanonicalHeaderKey(h)] = struct{}{}
	}
	result := make([]string, 0, len(m))
	for k := range m {
		result = append(result, k)
	}

	// Sort
	sort.Strings(result)
	return result
}

Lars Gierth's avatar
Lars Gierth committed
43
func GatewayOption(writable bool, paths ...string) ServeOption {
tavit ohanian's avatar
tavit ohanian committed
44
	return func(n *core.Dms3Node, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
45 46 47 48 49
		cfg, err := n.Repo.Config()
		if err != nil {
			return nil, err
		}

50
		api, err := coreapi.NewCoreAPI(n, options.Api.FetchBlocks(!cfg.Gateway.NoFetch))
51 52 53 54
		if err != nil {
			return nil, err
		}

Steven Allen's avatar
Steven Allen committed
55 56
		headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
		for h, v := range cfg.Gateway.HTTPHeaders {
57
			headers[http.CanonicalHeaderKey(h)] = v
Steven Allen's avatar
Steven Allen committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71
		}

		// Hard-coded headers.
		const ACAHeadersName = "Access-Control-Allow-Headers"
		const ACEHeadersName = "Access-Control-Expose-Headers"
		const ACAOriginName = "Access-Control-Allow-Origin"
		const ACAMethodsName = "Access-Control-Allow-Methods"

		if _, ok := headers[ACAOriginName]; !ok {
			// Default to *all*
			headers[ACAOriginName] = []string{"*"}
		}
		if _, ok := headers[ACAMethodsName]; !ok {
			// Default to GET
Steven Allen's avatar
Steven Allen committed
72
			headers[ACAMethodsName] = []string{http.MethodGet}
Steven Allen's avatar
Steven Allen committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
		}

		headers[ACAHeadersName] = cleanHeaderSet(
			append([]string{
				"Content-Type",
				"User-Agent",
				"Range",
				"X-Requested-With",
			}, headers[ACAHeadersName]...))

		headers[ACEHeadersName] = cleanHeaderSet(
			append([]string{
				"Content-Range",
				"X-Chunked-Output",
				"X-Stream-Output",
			}, headers[ACEHeadersName]...))

90
		gateway := newGatewayHandler(GatewayConfig{
Steven Allen's avatar
Steven Allen committed
91
			Headers:      headers,
Lars Gierth's avatar
Lars Gierth committed
92
			Writable:     writable,
93
			PathPrefixes: cfg.Gateway.PathPrefixes,
94
		}, api)
95

96 97
		for _, p := range paths {
			mux.Handle(p+"/", gateway)
98
		}
99
		return mux, nil
100
	}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
101
}
102

Jeromy's avatar
Jeromy committed
103
func VersionOption() ServeOption {
tavit ohanian's avatar
tavit ohanian committed
104
	return func(_ *core.Dms3Node, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
Jeromy's avatar
Jeromy committed
105
		mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
106
			fmt.Fprintf(w, "Commit: %s\n", version.CurrentCommit)
Steven Allen's avatar
Steven Allen committed
107
			fmt.Fprintf(w, "Client Version: %s\n", version.UserAgent)
tavit ohanian's avatar
tavit ohanian committed
108
			fmt.Fprintf(w, "Protocol Version: %s\n", id.P2PVersion)
Jeromy's avatar
Jeromy committed
109 110 111 112
		})
		return mux, nil
	}
}