Apply standard format, add dummy server

This commit is contained in:
Thomas Boerger
2019-09-16 10:11:08 +02:00
parent 18bf7dc120
commit f736c02c23
29 changed files with 1441 additions and 49 deletions

View File

@@ -10,7 +10,10 @@ def main(ctx):
binary('windows'),
]
after = manifest()
after = [
manifest(),
documentation()
]
for b in before:
for s in stages:
@@ -385,7 +388,7 @@ def binary(name):
}
def manifest():
return [{
return {
'kind': 'pipeline',
'type': 'docker',
'name': 'manifest',
@@ -424,4 +427,54 @@ def manifest():
'refs/tags/**'
]
}
}]
}
def documentation():
return {
'kind': 'pipeline',
'type': 'docker',
'name': 'documentation',
'platform': {
'os': 'linux',
'arch': 'amd64',
},
'steps': [
{
'name': 'generate',
'image': 'webhippie/hugo:latest',
'pull': 'always',
'commands': [
'make docs'
]
},
{
'name': 'publish',
'image': 'plugins/gh-pages:1',
'pull': 'always',
'settings': {
'username': {
'from_secret': 'github_username'
},
'password': {
'from_secret': 'github_token'
},
'pages_directory': 'docs/public/',
'temporary_base': 'tmp/',
},
'when': {
'event': {
'exclude': [
'pull_request'
]
}
}
}
],
'depends_on': [],
'trigger': {
'ref': [
'refs/heads/master',
'refs/pull/**'
]
}
}

View File

@@ -649,4 +649,48 @@ depends_on:
- darwin
- windows
---
kind: pipeline
type: docker
name: documentation
platform:
os: linux
arch: amd64
steps:
- name: generate
pull: always
image: webhippie/hugo:latest
commands:
- make docs
- name: publish
pull: always
image: plugins/gh-pages:1
settings:
pages_directory: docs/public/
password:
from_secret: github_token
temporary_base: tmp/
username:
from_secret: github_username
when:
event:
exclude:
- pull_request
trigger:
ref:
- refs/heads/master
- refs/pull/**
depends_on:
- amd64
- arm64
- arm
- linux
- darwin
- windows
...

View File

@@ -1,7 +1,8 @@
---
repository:
name: ocis-webdav
description: ':atom_symbol: Service to serve WebDAV for Reva/oCIS'
description: ':atom_symbol: Serve WebDAV API for Reva/oCIS'
homepage: https://owncloud.github.io/ocis-webdav/
topics: reva, ocis
private: false

View File

@@ -6,10 +6,8 @@ DIST := dist
ifeq ($(OS), Windows_NT)
EXECUTABLE := $(NAME).exe
HAS_GORUNPKG := $(shell where gorunpkg)
else
EXECUTABLE := $(NAME)
HAS_GORUNPKG := $(shell command -v gorunpkg)
endif
PACKAGES ?= $(shell go list ./...)
@@ -61,24 +59,24 @@ vet:
go vet $(PACKAGES)
.PHONY: staticcheck
staticcheck: gorunpkg
gorunpkg honnef.co/go/tools/cmd/staticcheck -tags '$(TAGS)' $(PACKAGES)
staticcheck:
go run honnef.co/go/tools/cmd/staticcheck -tags '$(TAGS)' $(PACKAGES)
.PHONY: lint
lint: gorunpkg
for PKG in $(PACKAGES); do gorunpkg golang.org/x/lint/golint -set_exit_status $$PKG || exit 1; done;
lint:
for PKG in $(PACKAGES); do go run golang.org/x/lint/golint -set_exit_status $$PKG || exit 1; done;
.PHONY: generate
generate: gorunpkg
generate:
go generate $(GENERATE)
.PHONY: changelog
changelog: gorunpkg
gorunpkg github.com/restic/calens >| CHANGELOG.md
changelog:
go run github.com/restic/calens >| CHANGELOG.md
.PHONY: test
test: gorunpkg
gorunpkg github.com/haya14busa/goverage -v -coverprofile coverage.out $(PACKAGES)
test:
go run github.com/haya14busa/goverage -v -coverprofile coverage.out $(PACKAGES)
.PHONY: install
install: $(SOURCES)
@@ -98,16 +96,16 @@ release-dirs:
mkdir -p $(DIST)/binaries $(DIST)/release
.PHONY: release-linux
release-linux: gorunpkg release-dirs
gorunpkg github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'linux' -arch 'amd64 386 arm64 arm' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
release-linux: release-dirs
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'linux' -arch 'amd64 386 arm64 arm' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
.PHONY: release-windows
release-windows: gorunpkg release-dirs
gorunpkg github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'windows' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
release-windows: release-dirs
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'windows' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
.PHONY: release-darwin
release-darwin: gorunpkg release-dirs
gorunpkg github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '$(LDFLAGS)' -os 'darwin' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
release-darwin: release-dirs
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '$(LDFLAGS)' -os 'darwin' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
.PHONY: release-copy
release-copy:
@@ -120,8 +118,6 @@ release-check:
.PHONY: release-finish
release-finish: release-copy release-check
.PHONY: gorunpkg
gorunpkg:
ifndef HAS_GORUNPKG
go get -u github.com/vektah/gorunpkg
endif
.PHONY: docs
docs:
cd docs; hugo

View File

@@ -0,0 +1,6 @@
---
title: "{{ replace .TranslationBaseName "-" " " | title }}"
date: {{ .Date }}
anchor: "{{ replace .TranslationBaseName "-" " " | title | urlize }}"
weight:
---

16
docs/config.toml Normal file
View File

@@ -0,0 +1,16 @@
baseURL = "https://owncloud.github.io/ocis-webdav/"
languageCode = "en-us"
title = "ownCloud Infinite Scale: WebDAV"
pygmentsUseClasses = true
[blackfriday]
angledQuotes = true
fractions = false
plainIDAnchors = true
smartlists = true
extensions = ["hardLineBreak"]
[params]
author = "ownCloud GmbH"
description = "Serve WebDAV API for Reva/oCIS"
keywords = "reva, ocis"

8
docs/content/about.md Normal file
View File

@@ -0,0 +1,8 @@
---
title: "About"
date: 2018-05-02T00:00:00+00:00
anchor: "about"
weight: 10
---
TBD

28
docs/content/building.md Normal file
View File

@@ -0,0 +1,28 @@
---
title: "Building"
date: 2018-05-02T00:00:00+00:00
anchor: "building"
weight: 30
---
As this project is built with Go, so you need to install that first. The installation of Go is out of the scope of this document, please follow the official documentation for [Go](golang). After the installation of the required tools you need to get the sources:
{{< highlight txt >}}
git clone https://github.com/owncloud/ocis-webdav.git
cd ocis-webdav
{{< / highlight >}}
All required tool besides Go itself and make are bundled or getting automatically installed within the `GOPATH`. All commands to build this project are part of our `Makefile` and respectively our `package.json`.
## Backend
{{< highlight txt >}}
make generate
make build
{{< / highlight >}}
Finally you should have the binary within the `bin/` folder now, give it a try with `./bin/ocis-webdav -h` to see all available options.
[golang]: https://golang.org/doc/install
[nodejs]: https://nodejs.org/en/download/package-manager/
[yarn]: https://yarnpkg.com/lang/en/docs/install/

View File

@@ -0,0 +1,224 @@
---
title: "Getting Started"
date: 2018-05-02T00:00:00+00:00
anchor: "getting-started"
weight: 20
---
## Installation
So far we are offering two different variants for the installation. You can choose between [Docker](docker) or pre-built binaries which are stored on our download mirrors and GitHub releases. Maybe we will also provide system packages for the major distributions later if we see the need for it.
### Docker
TBD
### Binaries
TBD
## Configuration
We provide overall three different variants of configuration. The variant based on environment variables and commandline flags are split up into global values and command-specific values.
### Envrionment variables
If you prefer to configure the service with environment variables you can see the available variables below.
#### Global
WEBDAV_LOG_LEVEL
: Set logging level, defaults to `info`
WEBDAV_LOG_COLOR
: Enable colored logging, defaults to `true`
WEBDAV_LOG_PRETTY
: Enable pretty logging, defaults to `true`
#### Server
WEBDAV_DEBUG_ADDR
: Address to bind debug server, defaults to `0.0.0.0:8190`
WEBDAV_DEBUG_TOKEN
: Token to grant metrics access, empty default value
WEBDAV_DEBUG_PPROF
: Enable pprof debugging, defaults to `false`
WEBDAV_HTTP_ADDR
: Address to bind http server, defaults to `0.0.0.0:8180`
WEBDAV_HTTP_ROOT
: Root path for http endpoint, defaults to `/`
#### Health
WEBDAV_DEBUG_ADDR
: Address to debug endpoint, defaults to `0.0.0.0:8190`
### Commandline flags
If you prefer to configure the service with commandline flags you can see the available variables below.
#### Global
--log-level
: Set logging level, defaults to `info`
--log-color
: Enable colored logging, defaults to `true`
--log-pretty
: Enable pretty logging, defaults to `true`
#### Server
--debug-addr
: Address to bind debug server, defaults to `0.0.0.0:8190`
--debug-token
: Token to grant metrics access, empty default value
--debug-pprof
: Enable pprof debugging, defaults to `false`
--http-addr
: Address to bind http server, defaults to `0.0.0.0:8180`
--http-root
: Root path for http endpoint, defaults to `/`
#### Health
--debug-addr
: Address to debug endpoint, defaults to `0.0.0.0:8190`
### Configuration file
So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](repo), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/webdav.yml`, `${HOME}/.ocis/webdav.yml` or `$(pwd)/config/webdav.yml`.
## Usage
The program provides a few sub-commands on execution. The available configuration methods have already been mentioned above. Generally you can always see a formated help output if you execute the binary via `ocis-webdav --help`.
### Server
The server command is used to start the http and debug server on two addresses within a single process. The http server is serving the general webservice while the debug server is used for health check, readiness check and to server the metrics mentioned below. For further help please execute:
{{< highlight txt >}}
ocis-webdav server --help
{{< / highlight >}}
### Health
The health command is used to execute a health check, if the exit code equals zero the service should be up and running, if the exist code is greater than zero the service is not in a healthy state. Generally this command is used within our Docker containers, it could also be used within Kubernetes.
{{< highlight txt >}}
ocis-webdav health --help
{{< / highlight >}}
## Metrics
This service provides some [Prometheus](prom) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `WEBDAV_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:8190/metrics`.
go_gc_duration_seconds
: A summary of the GC invocation durations
go_gc_duration_seconds_sum
: A summary of the GC invocation durations
go_gc_duration_seconds_count
: A summary of the GC invocation durations
go_goroutines
: Number of goroutines that currently exist
go_info
: Information about the Go environment
go_memstats_alloc_bytes
: Number of bytes allocated and still in use
go_memstats_alloc_bytes_total
: Total number of bytes allocated, even if freed
go_memstats_buck_hash_sys_bytes
: Number of bytes used by the profiling bucket hash table
go_memstats_frees_total
: Total number of frees
go_memstats_gc_cpu_fraction
: The fraction of this program's available CPU time used by the GC since the program started
go_memstats_gc_sys_bytes
: Number of bytes used for garbage collection system metadata
go_memstats_heap_alloc_bytes
: Number of heap bytes allocated and still in use
go_memstats_heap_idle_bytes
: Number of heap bytes waiting to be used
go_memstats_heap_inuse_bytes
: Number of heap bytes that are in use
go_memstats_heap_objects
: Number of allocated objects
go_memstats_heap_released_bytes
: Number of heap bytes released to OS
go_memstats_heap_sys_bytes
: Number of heap bytes obtained from system
go_memstats_last_gc_time_seconds
: Number of seconds since 1970 of last garbage collection
go_memstats_lookups_total
: Total number of pointer lookups
go_memstats_mallocs_total
: Total number of mallocs
go_memstats_mcache_inuse_bytes
: Number of bytes in use by mcache structures
go_memstats_mcache_sys_bytes
: Number of bytes used for mcache structures obtained from system
go_memstats_mspan_inuse_bytes
: Number of bytes in use by mspan structures
go_memstats_mspan_sys_bytes
: Number of bytes used for mspan structures obtained from system
go_memstats_next_gc_bytes
: Number of heap bytes when next garbage collection will take place
go_memstats_other_sys_bytes
: Number of bytes used for other system allocations
go_memstats_stack_inuse_bytes
: Number of bytes in use by the stack allocator
go_memstats_stack_sys_bytes
: Number of bytes obtained from system for stack allocator
go_memstats_sys_bytes
: Number of bytes obtained from system
go_threads
: Number of OS threads created
promhttp_metric_handler_requests_in_flight
: Current number of scrapes being served
promhttp_metric_handler_requests_total
: Total number of scrapes by HTTP status code
[docker]: https://www.docker.com/
[repo]: https://github.com/owncloud/ocis-webdav/tree/master/config
[prom]: https://prometheus.io/

10
docs/content/license.md Normal file
View File

@@ -0,0 +1,10 @@
---
title: "License"
date: 2018-05-02T00:00:00+00:00
anchor: "license"
weight: 40
---
This project is licensed under the [Apache 2.0](license) license. For the license of the used libraries you have to check the respective sources.
[license]: https://github.com/owncloud/ocis-webdav/blob/master/LICENSE

View File

View File

57
docs/layouts/index.html Normal file
View File

@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html id="html" lang="{{ with .Site.LanguageCode }}{{ . }}{{ else }}en-US{{ end }}">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<meta name="viewport" content="width=device-width"/>
<title>
{{ .Site.Title }}
</title>
<meta name="description" content="{{ with .Site.Params.description }}{{ . }}{{ end }}">
<meta name="author" content="{{ with .Site.Params.author }}{{ . }}{{ end }}">
{{ partial "style.html" . }}
</head>
<body>
<section id="Menu">
<header>
<h1>
{{ .Site.Title }}
</h1>
<p>
{{ .Site.Params.description }}
</p>
</header>
<nav>
{{ range .Data.Pages.ByWeight }}
<a href="#{{ .Params.anchor }}">
{{ .Title }}
</a>
{{ end }}
</nav>
</section>
{{ range .Data.Pages.ByWeight }}
<section id="{{ .Params.anchor }}">
<h1>
<a href="#{{ .Params.anchor }}">
{{ .Title }}
</a>
<small>
<a href="#html">
Back to Top
</a>
</small>
</h1>
{{ .Content | markdownify }}
</section>
{{ end }}
</body>
</html>

View File

@@ -0,0 +1,337 @@
<link rel="stylesheet" href="syntax.css" />
<style type="text/css">
body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
form,
fieldset,
input,
textarea,
p,
blockquote,
th,
td {
margin: 0;
padding: 0;
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
:before,
:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
img,
object,
embed {
max-width: 100%;
height: auto;
}
object,
embed {
height: 100%;
}
img {
margin: 1.25% 0;
-ms-interpolation-mode: bicubic;
}
html {
background-color: #F0F1F3;
padding: 2%;
}
body {
font-size: 16px;
line-height: 1.6;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
color: #242424;
max-width: 800px;
margin: 5% auto;
}
body::after {
clear: both;
content: "";
display: table;
}
header {
margin-bottom: 8%;
}
footer {
text-align: center;
}
h1,
h2,
h3,
h4,
h5,
h1 a {
color: #263A48;
font-weight: 500;
text-decoration: none;
}
h1,
h2 {
font-size: 36px;
padding-bottom: 0.3em;
margin-bottom: 0.4em;
border-bottom: 1px solid #eee
}
h2 {
font-size: 22px;
padding-bottom: 0.6em;
margin-bottom: 0.6em;
margin-top: 2.5em;
}
h3 {
font-size: 18px;
margin-bottom: 0.3em;
}
h1 small a {
color: #98999C;
font-size: 15px;
font-weight: normal;
float: right;
position: absolute;
top: 15px;
right: 20px;
}
section {
background: #fff;
margin-bottom: 1%;
position: relative;
padding: 6% 8%;
}
blockquote {
border-left: 3px solid #d54e21;
font-size: 16px;
padding: 0 0 0 20px;
color: #d54e21;
}
blockquote a {
color: #d54e21;
font-weight: 500;
}
blockquote code {
color: #d54e21;
}
.highlight pre {
padding: 10px;
}
.highlight {
margin-bottom: 4%;
}
a {
color: #1e8cbe;
text-decoration: underline;
}
a:hover {
color: #d54e21;
}
ul {
list-style: none;
}
ol {
list-style: number;
}
ol li {
color: #98999C;
margin-bottom: 5px;
}
ol li:last-child {
margin-bottom: 0;
}
p,
ul,
ol,
blockquote {
margin-bottom: 4%;
}
ul ul {
padding-top: 0;
margin-bottom: 0;
margin-left: 4%;
}
ul ul li:before {
content: '-';
display: inline-block;
padding-right: 2%;
}
ul.col-2 {
color: #98999C;
-webkit-column-count: 2;
-moz-column-count: 2;
column-count: 2;
-webkit-column-gap: 20px;
-moz-column-gap: 20px;
column-gap: 20px;
}
dl dt {
font-weight: bold;
}
dl dd {
padding-left: 10px;
}
@media screen and (min-width: 500px) {
ul.col-2 {
-webkit-column-count: 3;
-moz-column-count: 3;
column-count: 3;
-webkit-column-gap: 20px;
-moz-column-gap: 20px;
column-gap: 20px;
}
}
nav {
background: #F0F1F3;
min-width: 215px;
margin-bottom: 5px;
margin-top: 15px;
}
nav:first-of-type a {
color: #d54e21;
border-radius: 0;
}
nav:first-of-type a:hover {
color: #d54e21;
}
nav:first-of-type a:before {
background-color: #d54e21;
}
nav.affix {
position: fixed;
top: 20px;
}
nav.affix-bottom {
position: absolute;
}
nav a {
border-radius: 3px;
font-size: 15px;
display: block;
cursor: pointer;
font-weight: 500;
position: relative;
text-decoration: none;
padding: 10px 12px;
width: 100%;
padding-right: 3px;
border-bottom: 2px solid #fff;
}
nav a:before {
content: '';
width: 4px;
display: block;
left: 0;
position: absolute;
height: 100%;
display: none;
background: #1e8cbe;
top: 0;
}
nav a:hover {
background-color: #E6E8EA;
color: #1e8cbe;
text-decoration: underline;
}
nav a:hover:before {
display: block;
}
nav a:last-of-type {
border-bottom: none;
}
.gist {
margin-top: 5.1%;
margin-bottom: 5%;
}
@media screen and (max-width: 1050px) {
body {
margin: 0 auto;
}
}
@media screen and (max-width: 767px) {
header span {
display: none;
}
h1 {
font-size: 26px;
}
h2 {
font-size: 20px;
}
}
@media screen and (max-width: 514px) {
p,
ul,
ol,
blockquote {
margin-bottom: 8%;
}
}
</style>

59
docs/static/syntax.css vendored Normal file
View File

@@ -0,0 +1,59 @@
/* Background */ .chroma { color: #f8f8f2; background-color: #272822 }
/* Error */ .chroma .err { color: #960050; background-color: #1e0010 }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
/* Keyword */ .chroma .k { color: #66d9ef }
/* KeywordConstant */ .chroma .kc { color: #66d9ef }
/* KeywordDeclaration */ .chroma .kd { color: #66d9ef }
/* KeywordNamespace */ .chroma .kn { color: #f92672 }
/* KeywordPseudo */ .chroma .kp { color: #66d9ef }
/* KeywordReserved */ .chroma .kr { color: #66d9ef }
/* KeywordType */ .chroma .kt { color: #66d9ef }
/* NameAttribute */ .chroma .na { color: #a6e22e }
/* NameClass */ .chroma .nc { color: #a6e22e }
/* NameConstant */ .chroma .no { color: #66d9ef }
/* NameDecorator */ .chroma .nd { color: #a6e22e }
/* NameException */ .chroma .ne { color: #a6e22e }
/* NameFunction */ .chroma .nf { color: #a6e22e }
/* NameOther */ .chroma .nx { color: #a6e22e }
/* NameTag */ .chroma .nt { color: #f92672 }
/* Literal */ .chroma .l { color: #ae81ff }
/* LiteralDate */ .chroma .ld { color: #e6db74 }
/* LiteralString */ .chroma .s { color: #e6db74 }
/* LiteralStringAffix */ .chroma .sa { color: #e6db74 }
/* LiteralStringBacktick */ .chroma .sb { color: #e6db74 }
/* LiteralStringChar */ .chroma .sc { color: #e6db74 }
/* LiteralStringDelimiter */ .chroma .dl { color: #e6db74 }
/* LiteralStringDoc */ .chroma .sd { color: #e6db74 }
/* LiteralStringDouble */ .chroma .s2 { color: #e6db74 }
/* LiteralStringEscape */ .chroma .se { color: #ae81ff }
/* LiteralStringHeredoc */ .chroma .sh { color: #e6db74 }
/* LiteralStringInterpol */ .chroma .si { color: #e6db74 }
/* LiteralStringOther */ .chroma .sx { color: #e6db74 }
/* LiteralStringRegex */ .chroma .sr { color: #e6db74 }
/* LiteralStringSingle */ .chroma .s1 { color: #e6db74 }
/* LiteralStringSymbol */ .chroma .ss { color: #e6db74 }
/* LiteralNumber */ .chroma .m { color: #ae81ff }
/* LiteralNumberBin */ .chroma .mb { color: #ae81ff }
/* LiteralNumberFloat */ .chroma .mf { color: #ae81ff }
/* LiteralNumberHex */ .chroma .mh { color: #ae81ff }
/* LiteralNumberInteger */ .chroma .mi { color: #ae81ff }
/* LiteralNumberIntegerLong */ .chroma .il { color: #ae81ff }
/* LiteralNumberOct */ .chroma .mo { color: #ae81ff }
/* Operator */ .chroma .o { color: #f92672 }
/* OperatorWord */ .chroma .ow { color: #f92672 }
/* Comment */ .chroma .c { color: #75715e }
/* CommentHashbang */ .chroma .ch { color: #75715e }
/* CommentMultiline */ .chroma .cm { color: #75715e }
/* CommentSingle */ .chroma .c1 { color: #75715e }
/* CommentSpecial */ .chroma .cs { color: #75715e }
/* CommentPreproc */ .chroma .cp { color: #75715e }
/* CommentPreprocFile */ .chroma .cpf { color: #75715e }
/* GenericDeleted */ .chroma .gd { color: #f92672 }
/* GenericEmph */ .chroma .ge { font-style: italic }
/* GenericInserted */ .chroma .gi { color: #a6e22e }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #75715e }

3
go.mod
View File

@@ -3,8 +3,11 @@ module github.com/owncloud/ocis-webdav
go 1.12
require (
github.com/go-chi/chi v4.0.2+incompatible
github.com/haya14busa/goverage v0.0.0-20180129164344-eec3514a20b5 // indirect
github.com/mitchellh/gox v1.0.1 // indirect
github.com/oklog/run v1.0.0
github.com/prometheus/client_golang v0.9.3
github.com/restic/calens v0.0.0-20190419101620-10f36cb4a529 // indirect
github.com/rs/zerolog v1.15.0
github.com/spf13/cobra v0.0.5

13
go.sum
View File

@@ -6,6 +6,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -23,6 +24,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -34,6 +37,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -62,6 +66,7 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
@@ -71,6 +76,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -79,17 +86,22 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/restic/calens v0.0.0-20190419101620-10f36cb4a529 h1:TPB3vbGNwppek0lcfpKG8rVRtvr5D78d/1MnlbfNfgA=
github.com/restic/calens v0.0.0-20190419101620-10f36cb4a529/go.mod h1:I3AyHROuWXtWtZtI5ApjLbnN0si15sWvPQO7ul4gDow=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
@@ -118,6 +130,7 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=

15
pkg/command/default.go Normal file
View File

@@ -0,0 +1,15 @@
package command
import (
"github.com/spf13/viper"
)
// init defined the default options for viper.
func init() {
viper.SetDefault("debug.addr", "0.0.0.0:8190")
viper.SetDefault("debug.token", "")
viper.SetDefault("debug.pprof", false)
viper.SetDefault("http.addr", "0.0.0.0:8180")
viper.SetDefault("http.root", "/")
}

View File

@@ -1,10 +0,0 @@
package command
import (
"github.com/spf13/viper"
)
func init() {
viper.SetDefault("server.addr", "0.0.0.0:8180")
viper.SetDefault("metrics.addr", "0.0.0.0:8190")
}

View File

@@ -1,6 +1,10 @@
package command
import (
"fmt"
"net/http"
"os"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -13,15 +17,38 @@ func Health() *cobra.Command {
Short: "Check health status",
Long: "",
Run: func(cmd *cobra.Command, args []string) {
log.Info().
Str("addr", viper.GetString("metrics.addr")).
Msg("Executed health command")
resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
viper.GetString("debug.addr"),
),
)
if err != nil {
log.Error().
Err(err).
Msg("Failed to request health check")
os.Exit(1)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
log.Error().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
os.Exit(1)
}
os.Exit(0)
},
}
cmd.Flags().String("metrics-addr", "", "Address to metrics endpoint")
viper.BindPFlag("metrics.addr", cmd.Flags().Lookup("metrics-addr"))
viper.BindEnv("metrics.addr", "WEBDAV_METRICS_ADDR")
cmd.Flags().String("debug-addr", "", "Address to debug endpoint")
viper.BindPFlag("debug.addr", cmd.Flags().Lookup("debug-addr"))
viper.BindEnv("debug.addr", "WEBDAV_DEBUG_ADDR")
return cmd
}

View File

@@ -45,6 +45,7 @@ func Root() *cobra.Command {
return cmd
}
// setupLogger prepares the logger.
func setupLogger() {
switch strings.ToLower(viper.GetString("log.level")) {
case "panic":
@@ -73,6 +74,7 @@ func setupLogger() {
}
}
// setupConfig prepares the config.
func setupConfig() {
viper.SetConfigName("webdav")

View File

@@ -1,6 +1,17 @@
package command
import (
"context"
"net"
"net/http"
"os"
"os/signal"
"strings"
"time"
"github.com/oklog/run"
"github.com/owncloud/ocis-webdav/pkg/router/debug"
"github.com/owncloud/ocis-webdav/pkg/router/server"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -12,16 +23,215 @@ func Server() *cobra.Command {
Use: "server",
Short: "Start integrated server",
Long: "",
Run: func(cmd *cobra.Command, args []string) {
log.Info().
Str("addr", viper.GetString("server.addr")).
Msg("Executed server command")
RunE: func(cmd *cobra.Command, args []string) error {
var gr run.Group
{
server := &http.Server{
Addr: viper.GetString("debug.addr"),
Handler: debug.Router(
debug.WithToken(viper.GetString("debug.token")),
debug.WithPprof(viper.GetBool("debug.pprof")),
),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
gr.Add(func() error {
log.Info().
Str("addr", viper.GetString("debug.addr")).
Msg("Starting debug server")
if strings.HasPrefix(viper.GetString("debug.addr"), "unix://") {
socket := strings.TrimPrefix(viper.GetString("debug.addr"), "unix://")
if err := os.Remove(socket); err != nil && !os.IsNotExist(err) {
log.Error().
Err(err).
Str("socket", socket).
Msg("Failed to remove existing debug socket")
return err
}
listener, err := net.ListenUnix(
"unix",
&net.UnixAddr{
Name: socket,
Net: "unix",
},
)
if err != nil {
log.Error().
Err(err).
Msg("Failed to initialize debug unix socket")
return err
}
if err = os.Chmod(socket, os.FileMode(0666)); err != nil {
log.Error().
Err(err).
Msg("Failed to change debug socket permissions")
return err
}
return server.Serve(listener)
}
return server.ListenAndServe()
}, func(reason error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Error().
Err(err).
Msg("Failed to shutdown debug server gracefully")
return
}
if strings.HasPrefix(viper.GetString("debug.addr"), "unix://") {
socket := strings.TrimPrefix(viper.GetString("debug.addr"), "unix://")
if err := os.Remove(socket); err != nil && !os.IsNotExist(err) {
log.Error().
Err(err).
Str("socket", socket).
Msg("Failed to remove debug server socket")
}
}
log.Info().
Err(reason).
Msg("Shutdown debug server gracefully")
})
}
{
server := &http.Server{
Addr: viper.GetString("http.addr"),
Handler: server.Router(
server.WithRoot(viper.GetString("http.root")),
),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
gr.Add(func() error {
log.Info().
Str("addr", viper.GetString("http.addr")).
Msg("Starting http server")
if strings.HasPrefix(viper.GetString("http.addr"), "unix://") {
socket := strings.TrimPrefix(viper.GetString("http.addr"), "unix://")
if err := os.Remove(socket); err != nil && !os.IsNotExist(err) {
log.Error().
Err(err).
Str("socket", socket).
Msg("Failed to remove existing http socket")
return err
}
listener, err := net.ListenUnix(
"unix",
&net.UnixAddr{
Name: socket,
Net: "unix",
},
)
if err != nil {
log.Error().
Err(err).
Msg("Failed to initialize http unix socket")
return err
}
if err = os.Chmod(socket, os.FileMode(0666)); err != nil {
log.Error().
Err(err).
Msg("Failed to change http socket permissions")
return err
}
return server.Serve(listener)
}
return server.ListenAndServe()
}, func(reason error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Error().
Err(err).
Msg("Failed to shutdown http server gracefully")
return
}
if strings.HasPrefix(viper.GetString("http.addr"), "unix://") {
socket := strings.TrimPrefix(viper.GetString("http.addr"), "unix://")
if err := os.Remove(socket); err != nil && !os.IsNotExist(err) {
log.Error().
Err(err).
Str("socket", socket).
Msg("Failed to remove http server socket")
}
}
log.Info().
Err(reason).
Msg("Shutdown http server gracefully")
})
}
{
stop := make(chan os.Signal, 1)
gr.Add(func() error {
signal.Notify(stop, os.Interrupt)
<-stop
return nil
}, func(err error) {
close(stop)
})
}
return gr.Run()
},
}
cmd.Flags().String("server-addr", "", "Address to bind the server")
viper.BindPFlag("server.addr", cmd.Flags().Lookup("server-addr"))
viper.BindEnv("server.addr", "WEBDAV_SERVER_ADDR")
cmd.Flags().String("debug-addr", "", "Address to bind debug server")
viper.BindPFlag("debug.addr", cmd.Flags().Lookup("debug-addr"))
viper.BindEnv("debug.addr", "WEBDAV_DEBUG_ADDR")
cmd.Flags().String("debug-token", "", "Token to grant metrics access")
viper.BindPFlag("debug.token", cmd.Flags().Lookup("debug-token"))
viper.BindEnv("debug.token", "WEBDAV_DEBUG_TOKEN")
cmd.Flags().Bool("debug-pprof", false, "Enable pprof debugging")
viper.BindPFlag("debug.pprof", cmd.Flags().Lookup("debug-pprof"))
viper.BindEnv("debug.pprof", "WEBDAV_DEBUG_PPROF")
cmd.Flags().String("http-addr", "", "Address to bind http server")
viper.BindPFlag("http.addr", cmd.Flags().Lookup("http-addr"))
viper.BindEnv("http.addr", "WEBDAV_HTTP_ADDR")
cmd.Flags().String("http-root", "", "Root path for http endpoint")
viper.BindPFlag("http.root", cmd.Flags().Lookup("http-root"))
viper.BindEnv("http.root", "WEBDAV_HTTP_ROOT")
return cmd
}

View File

@@ -0,0 +1,58 @@
package metrics
import (
"fmt"
"net/http"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/zerolog/log"
)
var (
// ErrInvalidToken is returned when the request token is invalid.
ErrInvalidToken = `Invalid or missing token`
)
// metrics gets initialized by New and provides the handler.
type metrics struct {
token string
}
// ServeHTTP just implements the http.Handler interface.
func (m metrics) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if m.token == "" {
promhttp.Handler().ServeHTTP(w, r)
return
}
header := r.Header.Get("Authorization")
if header == "" {
log.Debug().
Msg("Missing auth header")
http.Error(w, ErrInvalidToken, http.StatusUnauthorized)
return
}
if header != fmt.Sprintf("Bearer %s", m.token) {
log.Debug().
Msg("Invalid token provided")
http.Error(w, ErrInvalidToken, http.StatusUnauthorized)
return
}
promhttp.Handler().ServeHTTP(w, r)
}
// Handler returns the handler for metrics endpoint.
func Handler(opts ...Option) http.Handler {
m := new(metrics)
for _, opt := range opts {
opt(m)
}
return m
}

View File

@@ -0,0 +1,11 @@
package metrics
// Option configures an assets option.
type Option func(*metrics)
// WithToken returns an option to set a token.
func WithToken(val string) Option {
return func(m *metrics) {
m.token = val
}
}

View File

@@ -0,0 +1,60 @@
package header
import (
"net/http"
"time"
"github.com/owncloud/ocis-webdav/pkg/version"
)
// Cache writes required cache headers to all requests.
func Cache(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
w.Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
next.ServeHTTP(w, r)
})
}
// Options writes required option headers to all requests.
func Options(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "OPTIONS" {
next.ServeHTTP(w, r)
} else {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
w.Header().Set("Allow", "HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS")
w.WriteHeader(http.StatusOK)
}
})
}
// Secure writes required access headers to all requests.
func Secure(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-XSS-Protection", "1; mode=block")
if r.TLS != nil {
w.Header().Set("Strict-Transport-Security", "max-age=31536000")
}
next.ServeHTTP(w, r)
})
}
// Version writes the current version to the headers.
func Version(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-WEBDAV-VERSION", version.String)
next.ServeHTTP(w, r)
})
}

74
pkg/router/debug/debug.go Normal file
View File

@@ -0,0 +1,74 @@
package debug
import (
"io"
"net/http"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/owncloud/ocis-webdav/pkg/handler/metrics"
"github.com/owncloud/ocis-webdav/pkg/middleware/header"
"github.com/rs/zerolog/hlog"
"github.com/rs/zerolog/log"
)
// debug gets initialized by Router and configures the router.
type debug struct {
token string
pprof bool
}
// Router initializes a router for the debug server.
func Router(opts ...Option) *chi.Mux {
d := new(debug)
for _, opt := range opts {
opt(d)
}
mux := chi.NewRouter()
mux.Use(hlog.NewHandler(log.Logger))
mux.Use(hlog.RemoteAddrHandler("ip"))
mux.Use(hlog.URLHandler("path"))
mux.Use(hlog.MethodHandler("method"))
mux.Use(hlog.RequestIDHandler("request_id", "Request-Id"))
mux.Use(middleware.RealIP)
mux.Use(header.Version)
mux.Use(header.Cache)
mux.Use(header.Secure)
mux.Use(header.Options)
mux.Route("/", func(root chi.Router) {
if d.pprof {
root.Mount(
"/debug",
middleware.Profiler(),
)
}
root.Mount(
"/metrics",
metrics.Handler(
metrics.WithToken(d.token),
),
)
root.Get("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
io.WriteString(w, http.StatusText(http.StatusOK))
})
root.Get("/readyz", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
io.WriteString(w, http.StatusText(http.StatusOK))
})
})
return mux
}

View File

@@ -0,0 +1,18 @@
package debug
// Option configures an assets option.
type Option func(*debug)
// WithToken returns an option to set a token.
func WithToken(val string) Option {
return func(d *debug) {
d.token = val
}
}
// WithPprof returns an option to enable pprof.
func WithPprof(val bool) Option {
return func(d *debug) {
d.pprof = val
}
}

View File

@@ -0,0 +1,11 @@
package server
// Option configures an assets option.
type Option func(*server)
// WithRoot returns an option to set root.
func WithRoot(val string) Option {
return func(s *server) {
s.root = val
}
}

View File

@@ -0,0 +1,61 @@
package server
import (
"net/http"
"time"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/owncloud/ocis-webdav/pkg/middleware/header"
"github.com/rs/zerolog/hlog"
"github.com/rs/zerolog/log"
)
// server gets initialized by Router and configures the router.
type server struct {
root string
}
// Router initializes a router for the http server.
func Router(opts ...Option) *chi.Mux {
s := new(server)
for _, opt := range opts {
opt(s)
}
mux := chi.NewRouter()
mux.Use(hlog.NewHandler(log.Logger))
mux.Use(hlog.RemoteAddrHandler("ip"))
mux.Use(hlog.URLHandler("path"))
mux.Use(hlog.MethodHandler("method"))
mux.Use(hlog.RequestIDHandler("request_id", "Request-Id"))
mux.Use(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
hlog.FromRequest(r).Debug().
Str("method", r.Method).
Str("url", r.URL.String()).
Int("status", status).
Int("size", size).
Dur("duration", duration).
Msg("")
}))
mux.Use(middleware.RealIP)
mux.Use(header.Version)
mux.Use(header.Cache)
mux.Use(header.Secure)
mux.Use(header.Options)
mux.Route(s.root, func(root chi.Router) {
root.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusNotFound)
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
})
})
return mux
}