Skip to content

Commit

Permalink
feat(cache-control): new option USE_CONTROL_CACHE_HEADER adds `Cach…
Browse files Browse the repository at this point in the history
…e-Control` header on requests to registry server (#265)

This option requires registry configuration: `Access-Control-Allow-Headers` with `Cache-Control`
  • Loading branch information
Joxit authored Sep 12, 2022
1 parent 57a1cf9 commit 34fd13d
Show file tree
Hide file tree
Showing 7 changed files with 22 additions and 6 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ Some env options are available for use this interface for **only one server**.
- `READ_ONLY_REGISTRIES`: Desactivate dialog for remove and add new registries, available only when `SINGLE_REGISTRY=false`. (default: `false`).
- `SHOW_CATALOG_NB_TAGS`: Show number of tags per images on catalog page. This will produce + nb images requests, not recommended on large registries. (default: `false`).
- `HISTORY_CUSTOM_LABELS`: Expose custom labels in history page, custom labels will be processed like maintainer label.
- `USE_CONTROL_CACHE_HEADER`: Use `Control-Cache` header and set to `no-store, no-cache`. This will avoid some issues on multi-arch images (see [#260](https://github.com/Joxit/docker-registry-ui/issues/260)). This option requires registry configuration: `Access-Control-Allow-Headers` with `Cache-Control`. (default: `false`).

There are some examples with [docker-compose](https://docs.docker.com/compose/) and docker-registry-ui as proxy [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-proxy/) or docker-registry-ui as standalone [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-standalone/).

Expand All @@ -128,7 +129,7 @@ http:
headers:
Access-Control-Allow-Origin: ['http://registry.example.com']
Access-Control-Allow-Credentials: [true]
Access-Control-Allow-Headers: ['Authorization', 'Accept']
Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS'] # Optional
```
Expand All @@ -150,7 +151,7 @@ And you need to add these HEADERS:
http:
headers:
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
Access-Control-Allow-Headers: ['Authorization', 'Accept']
Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
Access-Control-Expose-Headers: ['Docker-Content-Digest']
```
Expand Down Expand Up @@ -178,7 +179,7 @@ http:
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Origin: ['http://127.0.0.1:8000']
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
Access-Control-Allow-Headers: ['Authorization', 'Accept']
Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
Access-Control-Max-Age: [1728000]
Access-Control-Allow-Credentials: [true]
Access-Control-Expose-Headers: ['Docker-Content-Digest']
Expand Down
1 change: 1 addition & 0 deletions bin/90-docker-registry-ui.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ sed -i "s~\${DEFAULT_REGISTRIES}~${DEFAULT_REGISTRIES}~" index.html
sed -i "s~\${READ_ONLY_REGISTRIES}~${READ_ONLY_REGISTRIES}~" index.html
sed -i "s~\${SHOW_CATALOG_NB_TAGS}~${SHOW_CATALOG_NB_TAGS}~" index.html
sed -i "s~\${HISTORY_CUSTOM_LABELS}~${HISTORY_CUSTOM_LABELS}~" index.html
sed -i "s~\${USE_CONTROL_CACHE_HEADER}~${USE_CONTROL_CACHE_HEADER}~" index.html

if [ -z "${DELETE_IMAGES}" ] || [ "${DELETE_IMAGES}" = false ] ; then
sed -i "s/\${DELETE_IMAGES}/false/" index.html
Expand Down
3 changes: 3 additions & 0 deletions src/components/docker-registry-ui.riot
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
on-notify="{ notifySnackbar }"
filter-results="{ state.filter }"
on-authentication="{ onAuthentication }"
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
></tag-list>
</route>
<route path="{baseRoute}taghistory/(.*)">
Expand All @@ -65,6 +66,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
on-notify="{ notifySnackbar }"
on-authentication="{ onAuthentication }"
history-custom-labels="{ stringToArray(props.historyCustomLabels) }"
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
></tag-history>
</route>
</router>
Expand Down Expand Up @@ -133,6 +135,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
this.state.name = props.name || stripHttps(props.registryUrl);
this.state.catalogElementsLimit = props.catalogElementsLimit || 100000;
this.state.pullUrl = this.pullUrl(this.state.registryUrl, props.pullUrl);
this.state.useControlCacheHeader = props.useControlCacheHeader;
},
onServerChange(registryUrl) {
this.update({
Expand Down
4 changes: 3 additions & 1 deletion src/components/tag-history/tag-history.riot
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
registryUrl: props.registryUrl,
onNotify: props.onNotify,
onAuthentication: props.onAuthentication,
useControlCacheHeader: props.useControlCacheHeader,
});
state.image.fillInfo();
},
Expand All @@ -66,14 +67,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
},
onTabChanged(arch, idx) {
const state = this.state;
const { registryUrl, onNotify } = this.props;
const { registryUrl, onNotify, useControlCacheHeader } = this.props;
state.elements = [];
state.image.variants[idx] =
state.image.variants[idx] ||
new DockerImage(this.props.image, arch.digest, {
list: false,
registryUrl,
onNotify,
useControlCacheHeader,
});
if (state.image.variants[idx].blobs) {
return this.processBlobs(state.image.variants[idx].blobs);
Expand Down
1 change: 1 addition & 0 deletions src/components/tag-list/tag-list.riot
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
registryUrl: props.registryUrl,
onNotify: props.onNotify,
onAuthentication: props.onAuthentication,
useControlCacheHeader: props.useControlCacheHeader,
})
)
.sort(compare);
Expand Down
2 changes: 2 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
read-only-registries="${READ_ONLY_REGISTRIES}"
show-catalog-nb-tags="${SHOW_CATALOG_NB_TAGS}"
history-custom-labels="${HISTORY_CUSTOM_LABELS}"
use-control-cache-header="${USE_CONTROL_CACHE_HEADER}"
>
</docker-registry-ui>
<!-- endbuild -->
Expand All @@ -60,6 +61,7 @@
single-registry="false"
show-catalog-nb-tags="true"
history-custom-labels="first_custom_labels,second_custom_labels"
use-control-cache-header="false"
>
</docker-registry-ui>
<!-- endbuild -->
Expand Down
10 changes: 8 additions & 2 deletions src/scripts/docker-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function compare(e1, e2) {
}

export class DockerImage {
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication }) {
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication, useControlCacheHeader }) {
this.name = name;
this.tag = tag;
this.chars = 0;
Expand All @@ -55,6 +55,7 @@ export class DockerImage {
registryUrl,
onNotify,
onAuthentication,
useControlCacheHeader,
};
this.ociImage = false;
observable(this);
Expand Down Expand Up @@ -143,6 +144,9 @@ export class DockerImage {
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json' +
(self.opts.list ? ', application/vnd.docker.distribution.manifest.list.v2+json' : '')
);
if (self.opts.useControlCacheHeader) {
oReq.setRequestHeader('Cache-Control', 'no-store, no-cache');
}
oReq.send();
}
getBlobs(blob) {
Expand All @@ -165,7 +169,9 @@ export class DockerImage {
self.trigger('creation-date', self.creationDate);
self.trigger('blobs', self.blobs);
} else if (this.status === 404) {
self.opts.onNotify(`Blobs for ${self.name}:${self.tag} not found`, true);
self.opts.onNotify(`Blobs for ${self.name}:${self.tag} not found: blob '${self.blobs}'`, true);
} else if (!this.responseText) {
self.opts.onNotify(`Can"t get blobs for ${self.name}:${self.tag}: blob '${self.blobs}' (no message error)`, true);
} else {
self.opts.onNotify(this.responseText);
}
Expand Down

0 comments on commit 34fd13d

Please sign in to comment.