diff --git a/docs/Makefile b/docs/Makefile index 1dba8c6..e98a8b7 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -51,15 +51,13 @@ dist-docs_versions: $(OUTPUT_DIR)/versions-$(CRYSTAL_VERSION).json ## Update `/v $(OUTPUT_DIR)/versions-$(CRYSTAL_VERSION).json: $(OUTPUT_DIR)/$(OUTPUT_DOCS_BASE_NAME).tar.gz .PHONY: dist-redirect_latest -dist-redirect_latest: $(OUTPUT_DIR)/aws-config.json ## Apply redirect from `api/latest` to `api/$(CRYSTAL_VERSION)` in S3 (needs to be manually applied) - $(AWS_CLI) s3api put-bucket-website --bucket "$(AWS_BUCKET)" --website-configuration "file://$<" +dist-redirect_latest: MATCH_CURRENT_ETAG = --name crystal-api-docs-redirects --if-match "$$($(AWS_CLI) cloudfront describe-function --name crystal-api-docs-redirects --output text --query 'ETag')" +dist-redirect_latest: $(OUTPUT_DIR)/aws-cloudfront-redirect.js ## Apply redirect from `api/latest` to `api/$(CRYSTAL_VERSION)` in CloudFront (needs to be manually applied) + $(AWS_CLI) cloudfront update-function $(MATCH_CURRENT_ETAG) --function-config '{"Runtime":"cloudfront-js-2.0","Comment":"Redirects for Crystal API docs $(CRYSTAL_VERSION)"}' --function-code "$(shell base64 -i $(OUTPUT_DIR)/aws-cloudfront-redirect.js)" + $(AWS_CLI) cloudfront publish-function $(MATCH_CURRENT_ETAG) -.PHONY: get-website-configuration -get-website-configuration: ## Pull website configuration from S3 bucket (run as `make pull-website-configuration -s > aws-config.json`) - $(AWS_CLI) s3api get-bucket-website --bucket "$(AWS_BUCKET)" - -.PHONY: $(OUTPUT_DIR)/aws-config.json -$(OUTPUT_DIR)/aws-config.json: aws-config.json $(OUTPUT_DIR) +.PHONY: $(OUTPUT_DIR)/aws-cloudfront-redirect.js +$(OUTPUT_DIR)/aws-cloudfront-redirect.js: aws-cloudfront-redirect.js $(OUTPUT_DIR) sed 's/$${CRYSTAL_VERSION}/$(CRYSTAL_VERSION)/g' "$<" > $@ .PHONY: help diff --git a/docs/aws-cloudfront-redirect.js b/docs/aws-cloudfront-redirect.js new file mode 100644 index 0000000..9ea6353 --- /dev/null +++ b/docs/aws-cloudfront-redirect.js @@ -0,0 +1,41 @@ +// Since CloudFront doesn't run functions when the origin returns a statusCode >=400 +// this function has to run upon "viewer request", before hitting the origin + +function redirect(path) { + return { + statusCode: 302, + headers: { + 'location': { value: path } + } + } +} + +const LATEST_INDEX_REDIRECTION_PATHS = [ '/api', '/api/', '/api/index.html', '/api/latest'] + +function handler(event) { + var requestPath = event.request.uri + + // well-known paths that should be queried as-is + if( + requestPath == '/api/versions.json' || + requestPath.startsWith('/api/1.') || + requestPath.startsWith('/api/0.') || + requestPath == '/api/master' || + requestPath.startsWith('/api/master/') + ) { + return event.request + } + + // prefixes that go to the current version's index + if(LATEST_INDEX_REDIRECTION_PATHS.includes(requestPath)) { + return redirect('/api/${CRYSTAL_VERSION}/') + } + + // "latest" prefix should be re-written to the current version + if(requestPath.startsWith('/api/latest/')) { + return redirect(requestPath.replace('/api/latest/', '/api/${CRYSTAL_VERSION}/')) + } + + // at this point, we assume the request omited the version - eg, `/api/String.html` + return redirect(requestPath.replace('/api/', '/api/${CRYSTAL_VERSION}/')) +} diff --git a/docs/aws-config.json b/docs/aws-config.json deleted file mode 100644 index f728846..0000000 --- a/docs/aws-config.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "IndexDocument": { - "Suffix": "index.html" - }, - "ErrorDocument": { - "Key": "api/${CRYSTAL_VERSION}/404.html" - }, - "RoutingRules": [ - { - "Condition": { - "HttpErrorCodeReturnedEquals": "404", - "KeyPrefixEquals": "api/1" - }, - "Redirect": { - "HostName": "crystal-lang.org", - "HttpRedirectCode": "302", - "Protocol": "https", - "ReplaceKeyWith": "api/${CRYSTAL_VERSION}/404.html" - } - }, - { - "Condition": { - "HttpErrorCodeReturnedEquals": "404", - "KeyPrefixEquals": "api/0" - }, - "Redirect": { - "HostName": "crystal-lang.org", - "HttpRedirectCode": "302", - "Protocol": "https", - "ReplaceKeyWith": "api/${CRYSTAL_VERSION}/404.html" - } - }, - { - "Condition": { - "KeyPrefixEquals": "api/latest/" - }, - "Redirect": { - "HostName": "crystal-lang.org", - "HttpRedirectCode": "302", - "Protocol": "https", - "ReplaceKeyPrefixWith": "api/${CRYSTAL_VERSION}/" - } - }, - { - "Condition": { - "HttpErrorCodeReturnedEquals": "404", - "KeyPrefixEquals": "api/" - }, - "Redirect": { - "HostName": "crystal-lang.org", - "HttpRedirectCode": "301", - "Protocol": "https", - "ReplaceKeyPrefixWith": "api/latest/" - } - } - ] -}