• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cinode / go / 3736023969

19 Dec 2022 11:26PM UTC coverage: 79.498%. First build
3736023969

push

github

Bartek
Basic test for the static_datastore binary

919 of 1156 relevant lines covered (79.5%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.33
/cmd/static_datastore/cmd/server.go
1
package cmd
2

3
import (
4
        "bufio"
5
        "bytes"
6
        "context"
7
        "encoding/hex"
8
        "fmt"
9
        "log"
10
        "net/http"
11
        "os"
12
        "path"
13
        "strings"
14

15
        "github.com/cinode/go/blenc"
16
        "github.com/cinode/go/common"
17
        "github.com/cinode/go/datastore"
18
        "github.com/cinode/go/structure"
19
        "github.com/spf13/cobra"
20
        "google.golang.org/protobuf/proto"
21
)
22

23
func serverCmd() *cobra.Command {
×
24

×
25
        var dataStoreDir string
×
26

×
27
        cmd := &cobra.Command{
×
28
                Use:   "server --datastore <datastore_dir>",
×
29
                Short: "Serve files from datastore on given folder",
×
30
                Long: `
×
31
Serve files from static datastore from a directory.
×
32
`,
×
33
                Run: func(cmd *cobra.Command, args []string) {
×
34
                        if dataStoreDir == "" {
×
35
                                cmd.Help()
×
36
                                return
×
37
                        }
×
38
                        server(dataStoreDir)
×
39
                },
40
        }
41

42
        cmd.Flags().StringVarP(&dataStoreDir, "datastore", "d", "", "Datastore directory containing blobs")
×
43

×
44
        return cmd
×
45
}
46

47
func getEntrypoint(datastoreDir string) ([]byte, blenc.KeyInfo, error) {
1✔
48
        ep, err := os.Open(path.Join(datastoreDir, "entrypoint.txt"))
1✔
49
        if err != nil {
1✔
50
                return nil, nil, fmt.Errorf("can't open entrypoint file from %s", datastoreDir)
×
51
        }
×
52
        defer ep.Close()
1✔
53

1✔
54
        scanner := bufio.NewScanner(ep)
1✔
55
        if !scanner.Scan() {
1✔
56
                return nil, nil, fmt.Errorf("malformed entrypoint file - missing bid")
×
57
        }
×
58
        bid, err := common.BlobNameFromString(scanner.Text())
1✔
59
        if err != nil {
1✔
60
                return nil, nil, fmt.Errorf("malformed entrypoint file - could not get blob name: %w", err)
×
61
        }
×
62

63
        if !scanner.Scan() {
1✔
64
                return nil, nil, fmt.Errorf("malformed entrypoint file - missing key info")
×
65
        }
×
66

67
        keyInfoText := strings.Split(scanner.Text(), ":")
1✔
68
        if len(keyInfoText) != 3 {
1✔
69
                return nil, nil, fmt.Errorf("malformed entrypoint file - invalid key info, must be 3 segments split by ':'")
×
70
        }
×
71
        keyType, err := hex.DecodeString(keyInfoText[0])
1✔
72
        if err != nil {
1✔
73
                return nil, nil, fmt.Errorf("malformed entrypoint file - invalid key info, key type segment can not be hex-decoded: %w", err)
×
74
        }
×
75
        if len(keyType) != 1 {
1✔
76
                return nil, nil, fmt.Errorf("malformed entrypoint file - invalid key info, key type segment must be one byte")
×
77
        }
×
78

79
        keyKey, err := hex.DecodeString(keyInfoText[1])
1✔
80
        if err != nil {
1✔
81
                return nil, nil, fmt.Errorf("malformed entrypoint file - invalid key info, key segment can not be hex-decoded: %w", err)
×
82
        }
×
83

84
        keyIV, err := hex.DecodeString(keyInfoText[2])
1✔
85
        if err != nil {
1✔
86
                return nil, nil, fmt.Errorf("malformed entrypoint file - invalid key info, IV can not be hex-decoded: %w", err)
×
87
        }
×
88
        return bid, blenc.NewStaticKeyInfo(
1✔
89
                keyType[0],
1✔
90
                keyKey,
1✔
91
                keyIV,
1✔
92
        ), nil
1✔
93
}
94

95
func handleDir(
96
        ctx context.Context,
97
        be blenc.BE,
98
        bid []byte,
99
        ki blenc.KeyInfo,
100
        w http.ResponseWriter,
101
        r *http.Request,
102
        subPath string,
103
) {
1✔
104

1✔
105
        if subPath == "" {
2✔
106
                subPath = "index.html"
1✔
107
        }
1✔
108

109
        pathParts := strings.SplitN(subPath, "/", 2)
1✔
110

1✔
111
        dirBytes := bytes.NewBuffer(nil)
1✔
112
        err := be.Read(ctx, common.BlobName(bid), ki, dirBytes)
1✔
113
        if err != nil {
1✔
114
                http.Error(w, "Internal error", http.StatusInternalServerError)
×
115
                return
×
116
        }
×
117

118
        dir := structure.Directory{}
1✔
119
        if err := proto.Unmarshal(dirBytes.Bytes(), &dir); err != nil {
1✔
120
                http.Error(w, "Internal error", http.StatusInternalServerError)
×
121
                return
×
122
        }
×
123

124
        entry, exists := dir.GetEntries()[pathParts[0]]
1✔
125
        if !exists {
2✔
126
                http.NotFound(w, r)
1✔
127
                return
1✔
128
        }
1✔
129

130
        if entry.GetMimeType() == "application/cinode-dir" {
2✔
131
                if len(pathParts) == 0 {
1✔
132
                        http.Redirect(w, r, r.URL.Path+"/", http.StatusPermanentRedirect)
×
133
                        return
×
134
                }
×
135
                handleDir(
1✔
136
                        ctx,
1✔
137
                        be,
1✔
138
                        entry.GetBid(),
1✔
139
                        blenc.NewStaticKeyInfo(
1✔
140
                                byte(entry.GetKeyInfo().GetType()),
1✔
141
                                entry.GetKeyInfo().GetKey(),
1✔
142
                                entry.GetKeyInfo().GetIv(),
1✔
143
                        ),
1✔
144
                        w, r,
1✔
145
                        pathParts[1],
1✔
146
                )
1✔
147
                return
1✔
148
        }
149

150
        if len(pathParts) > 1 {
1✔
151
                http.NotFound(w, r)
×
152
                return
×
153
        }
×
154

155
        w.Header().Set("Content-Type", entry.GetMimeType())
1✔
156
        err = be.Read(
1✔
157
                ctx,
1✔
158
                common.BlobName(entry.Bid),
1✔
159
                blenc.NewStaticKeyInfo(
1✔
160
                        byte(entry.GetKeyInfo().GetType()),
1✔
161
                        entry.GetKeyInfo().GetKey(),
1✔
162
                        entry.GetKeyInfo().GetIv(),
1✔
163
                ),
1✔
164
                w,
1✔
165
        )
1✔
166
        if err != nil {
1✔
167
                // TODO: Log this, can't send an error back, it's too late
×
168
        }
×
169
}
170

171
func serverHandler(datastoreDir string) (http.Handler, error) {
1✔
172
        epBID, epKI, err := getEntrypoint(datastoreDir)
1✔
173
        if err != nil {
1✔
174
                return nil, err
×
175
        }
×
176

177
        be := blenc.FromDatastore(datastore.InFileSystem(datastoreDir))
1✔
178

1✔
179
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2✔
180
                if r.Method != "GET" {
2✔
181
                        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
1✔
182
                        return
1✔
183
                }
1✔
184

185
                if strings.HasPrefix(r.URL.Path, "/") {
2✔
186
                        r.URL.Path = r.URL.Path[1:]
1✔
187
                }
1✔
188

189
                handleDir(r.Context(), be, epBID, epKI, w, r, r.URL.Path)
1✔
190
        }), nil
191
}
192

193
func server(datastoreDir string) {
×
194

×
195
        fmt.Println("Serving files from", datastoreDir)
×
196

×
197
        hnd, err := serverHandler(datastoreDir)
×
198
        if err != nil {
×
199
                log.Fatal(err)
×
200
        }
×
201
        http.Handle("/", hnd)
×
202

×
203
        fmt.Println("Listening on http://localhost:8080/")
×
204
        if err := http.ListenAndServe("0.0.0.0:8080", nil); err != nil {
×
205
                log.Fatalln(err)
×
206
        }
×
207
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc