├── requirements.txt ├── .gitignore ├── .github ├── bin │ └── waitHttp.sh └── workflows │ └── ci.yml ├── .platform └── nginx │ └── conf.d │ ├── prezi3.conf │ ├── showcase.conf │ ├── elasticbeanstalk │ ├── subfiles │ │ ├── image-api.conf │ │ └── iiif-website.conf │ └── 00_application.conf │ ├── beta.conf │ ├── prezi2to3.conf │ └── accepts.conf ├── Dockerfile ├── tests ├── TestIE.py ├── TestProxy.py ├── TestSharedCanvas.py ├── TestComingsoon.py ├── TestsFileSwitch.py ├── TestRDFXML.py ├── TestHttps.py ├── TestValidators.py ├── TestPrezi3.py ├── TestDomainNames.py ├── TestSuite.py ├── TestImageAPI.py ├── TestJsonLD.py ├── TestCORS.py └── TestRedirect.py ├── README.md ├── application.go ├── docker-files └── nginx.conf └── public └── index.html /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tests/__pycache__ 2 | tests/*.pyc 3 | *.swp 4 | -------------------------------------------------------------------------------- /.github/bin/waitHttp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | http_code=100 4 | while [ "$http_code" != "200" ] 5 | do 6 | sleep 5 7 | http_code=`curl --write-out %{http_code} --silent --output /dev/null "$1"` 8 | echo "$http_code"; 9 | done 10 | 11 | 12 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/prezi3.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | 5 | index index.html; 6 | 7 | server_name prezi3.iiif.io; 8 | return 301 http://iiif.io$request_uri; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | COPY docker-files/nginx.conf /etc/nginx/ 3 | RUN rm /etc/nginx/conf.d/*.conf 4 | COPY .platform/nginx/conf.d/*.conf /etc/nginx/conf.d/ 5 | COPY .platform/nginx/conf.d/elasticbeanstalk /etc/nginx/conf.d/elasticbeanstalk 6 | EXPOSE 80 7 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/showcase.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | 5 | index index.html; 6 | 7 | server_name showcase.iiif.io demos.iiif.io demo.iiif.io; 8 | 9 | return 301 https://iiif.io/demos/; 10 | } 11 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/elasticbeanstalk/subfiles/image-api.conf: -------------------------------------------------------------------------------- 1 | proxy_redirect off; 2 | proxy_set_header HOST image-api.iiif.io; 3 | proxy_set_header X-Forwarded-Proto $scheme; 4 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 5 | # note don't add slash at end if you want the full input path i.e. /api/image. If a slash is added it replaces everything in the location 6 | # match with / 7 | proxy_pass http://image-api.iiif.io; 8 | proxy_hide_header 'Access-Control-Allow-Origin'; 9 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/elasticbeanstalk/subfiles/iiif-website.conf: -------------------------------------------------------------------------------- 1 | proxy_set_header Authorization ''; 2 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 3 | proxy_set_header X-Real-IP $remote_addr; 4 | proxy_hide_header Access-Control-Request-Method; 5 | proxy_set_header Access-Control-Request-Method GET; 6 | proxy_hide_header x-amz-id-2; 7 | proxy_hide_header x-amz-request-id; 8 | proxy_intercept_errors on; 9 | proxy_pass http://iiif-website.s3-website-us-east-1.amazonaws.com; 10 | proxy_hide_header 'Access-Control-Allow-Origin'; -------------------------------------------------------------------------------- /tests/TestIE.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | from urllib.request import urlopen 4 | from urllib import request 5 | import os 6 | 7 | class TestIE(unittest.TestCase): 8 | baseurl = '' 9 | def setUp(self): 10 | self.baseurl = os.environ["baseurl"] 11 | 12 | def test_ieheader(self): 13 | url = '%s/%s' % (self.baseurl, 'index.html') 14 | response=urlopen(url) 15 | ieHeader=response.info().get('X-UA-Compatible') 16 | self.assertEqual(ieHeader, 'IE=Edge,chrome=1', 'Missing IE header') 17 | 18 | if __name__ == '__main__': 19 | unittest.main() 20 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/beta.conf: -------------------------------------------------------------------------------- 1 | # Check if client is capable of handling webp 2 | map $http_accept $webp_suffix { 3 | default ".png"; 4 | "~*webp" ".webp"; 5 | } 6 | 7 | # Capture image path, without the file extension 8 | map $uri $image { 9 | ~*^/(assets/images/heroes)/(.+)\..*$ /$1/$2; 10 | } 11 | 12 | server { 13 | listen 80; 14 | listen [::]:80; 15 | 16 | index index.html; 17 | 18 | server_name beta.iiif.io; 19 | 20 | add_header 'Access-Control-Allow-Origin' '*'; 21 | rewrite ^(.*)$ https://iiif.io$1 redirect; 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IIIF Reverse Proxy config 2 | 3 | This repo is merely for the `.ebextensions` directory to configure a nginx 4 | reverse proxy to S3 buckets serving static content. 5 | 6 | ## Running tests: 7 | 8 | Start nginx and run: 9 | ```./tests/TestSuite.py``` 10 | 11 | ## Runnning docker: 12 | ```docker build -t proxy . && docker run --rm --name proxy -p 9001:80 proxy:latest``` 13 | 14 | ## Config files 15 | 16 | Anything in .ebextensions/nginx/conf.d/ directory is in the http part of the nginx config. 17 | 18 | Anything in .ebextensions/nginx/conf.d/elasticbeanstalk is in the default server part of the nginx config. 19 | 20 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/prezi2to3.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | 5 | index index.html; 6 | 7 | server_name prezi2to3.iiif.io; 8 | 9 | location / { 10 | proxy_set_header Host ec2-54-197-21-214.compute-1.amazonaws.com; 11 | proxy_set_header Authorization ''; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header X-Real-IP $remote_addr; 14 | proxy_hide_header x-amz-id-2; 15 | proxy_hide_header x-amz-request-id; 16 | proxy_intercept_errors on; 17 | proxy_pass http://54.156.178.110:8000/; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/accepts.conf: -------------------------------------------------------------------------------- 1 | map $http_accept $jsonmimetype { 2 | default "application/json"; 3 | "application/ld+json" "application/ld+json"; 4 | } 5 | map $uri $custom_content_type { 6 | default "text/html"; 7 | ~(.*\.xml)$ "application/rdf+xml"; 8 | } 9 | 10 | map $http_accept $version { 11 | default "3"; 12 | "~http://iiif.io/api/presentation/2/context.json" "2"; 13 | "~http://iiif.io/api/presentation/3/context.json" "3"; 14 | } 15 | 16 | map $http_accept $webp_suffix { 17 | default ".png"; 18 | "~*webp" ".webp"; 19 | } 20 | map $http_accept $webp_format { 21 | default "png"; 22 | "~*webp" "webp"; 23 | } 24 | 25 | # Capture image path, without the file extension 26 | map $uri $image { 27 | ~*^/(assets/images/heroes)/(.+)\..*$ /$1/$2; 28 | } 29 | -------------------------------------------------------------------------------- /tests/TestProxy.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | import os 4 | from urllib.request import urlopen 5 | from urllib import request 6 | 7 | class TestProxy(unittest.TestCase): 8 | baseurl = '' 9 | def setUp(self): 10 | self.baseurl = os.environ["baseurl"] 11 | def test_website(self): 12 | url = '%s/%s' % (self.baseurl, 'technical-details/index.html') 13 | code = 0 14 | try: 15 | response=urlopen(url) 16 | code = response.code 17 | except request.HTTPError as error: 18 | code = error.code 19 | self.assertEqual(code,200, 'Problem retriving the main website got: %s from %s' % (code, url)) 20 | 21 | def test_api(self): 22 | url = '%s/%s' % (self.baseurl, 'api/index.html') 23 | code = 0 24 | try: 25 | response=urlopen(url) 26 | code = response.code 27 | except request.HTTPError as error: 28 | code = error.code 29 | self.assertEqual(code,200, 'Problem retriving the api website fot: %s from %s' % (code, url)) 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /application.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | port := os.Getenv("PORT") 12 | if port == "" { 13 | port = "5000" 14 | } 15 | 16 | f, _ := os.Create("/var/log/golang/golang-server.log") 17 | defer f.Close() 18 | log.SetOutput(f) 19 | 20 | const indexPage = "public/index.html" 21 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 22 | if r.Method == "POST" { 23 | if buf, err := ioutil.ReadAll(r.Body); err == nil { 24 | log.Printf("Received message: %s\n", string(buf)) 25 | } 26 | } else { 27 | log.Printf("Serving %s to %s...\n", indexPage, r.RemoteAddr) 28 | http.ServeFile(w, r, indexPage) 29 | } 30 | }) 31 | 32 | log.Printf("Listening on port %s\n\n", port) 33 | http.ListenAndServe(":"+port, nil) 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v4 11 | 12 | - uses: actions/setup-python@v5 13 | with: 14 | python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax 15 | 16 | - uses: actions/cache@v4 17 | with: 18 | path: ${{ env.pythonLocation }} 19 | key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }} 20 | 21 | - name: Install requirements 22 | run: pip install -r requirements.txt 23 | 24 | - name: Building proxy 25 | run: docker build -t proxy . 26 | 27 | - name: Running Proxy 28 | run: docker run -d --rm --name proxy -p 9001:80 proxy:latest 29 | 30 | - name: Wait for Docker Website to start 31 | run: .github/bin/waitHttp.sh "http://localhost:9001/" 32 | 33 | - name: Run Tests 34 | run: python ./tests/TestSuite.py 35 | -------------------------------------------------------------------------------- /tests/TestSharedCanvas.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | import os 4 | import sys 5 | import requests 6 | try: 7 | import urlparse 8 | except: 9 | from urllib.parse import urlparse 10 | 11 | class TestSharedCanvas(unittest.TestCase): 12 | baseurl = '' 13 | desturl = '' 14 | def setUp(self): 15 | self.baseurl = os.environ["baseurl"] 16 | self.desturl = os.environ["desturl"] 17 | 18 | def checkOK(self,url): 19 | code = 0 20 | response = requests.get(url, allow_redirects=False) 21 | code = response.status_code 22 | self.assertEqual(code, 200, 'Failed to get 200 from host %s due to %s' % (url, code)) 23 | 24 | def test_checkPage(self): 25 | url = '{}/{}'.format(self.baseurl, 'api/model/shared-canvas/1.0/') 26 | self.checkOK(url) 27 | 28 | if __name__ == '__main__': 29 | baseurl = 'http://localhost:9001' 30 | if len(sys.argv) == 2: 31 | baseurl = sys.argv[1] 32 | 33 | os.environ["baseurl"] = baseurl 34 | os.environ["desturl"] = baseurl 35 | 36 | 37 | unittest.main() 38 | 39 | -------------------------------------------------------------------------------- /tests/TestComingsoon.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | import os 4 | import sys 5 | import requests 6 | 7 | class TestComingsoon(unittest.TestCase): 8 | baseurl = '' 9 | desturl = '' 10 | def setUp(self): 11 | self.baseurl = os.environ["baseurl"] 12 | self.desturl = os.environ["desturl"] 13 | 14 | def checkRedirect(self, source, target, host): 15 | code = 0 16 | response = requests.get(source, allow_redirects=False) 17 | code = response.status_code 18 | location = source 19 | if 'Location' in response.headers: 20 | location = response.headers['Location'] 21 | # print(code, location) 22 | self.assertEqual(code, 302, 'Failed to get redirected to %s due to %s' % (source, code)) 23 | self.assertEqual(location, target, 'Failed to redirect to the correct place. Expected %s but got %s' % (target, location)) 24 | 25 | 26 | def test_example(self): 27 | url = '%s/%s' % (self.baseurl, 'api/image/2.0/example/reference/67352ccc-d1b0-11e1-89ae-279075081939/info.json') 28 | dest = '%s/%s' % (self.desturl, 'comingsoon/') 29 | self.checkRedirect(url, dest,'0.0.0.0') 30 | 31 | if __name__ == '__main__': 32 | baseurl = 'http://localhost:5000' 33 | if len(sys.argv) == 2: 34 | baseurl = sys.argv[1] 35 | 36 | os.environ["baseurl"] = baseurl 37 | 38 | 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /tests/TestsFileSwitch.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | import os 4 | from urllib.request import urlopen 5 | from urllib import request 6 | import requests 7 | 8 | class TestFileSwitch(unittest.TestCase): 9 | baseurl = '' 10 | def setUp(self): 11 | self.baseurl = os.environ["baseurl"] 12 | 13 | def test_webp(self): 14 | url = '%s/%s' % (self.baseurl, 'assets/images/heroes/event_2.webp') 15 | code = 0 16 | try: 17 | response = requests.get(url, allow_redirects=False) 18 | code = response.status_code 19 | except request.HTTPError as error: 20 | code = error.code 21 | 22 | self.assertEqual(code, 200, 'Missing test webp %s from %s' % (code, url)) 23 | 24 | self.assertEqual(response.headers['content-type'], 'image/png', "Expected png as I didn't specify supports webp") 25 | 26 | try: 27 | response = requests.get(url, headers={ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8" }, allow_redirects=False) 28 | code = response.status_code 29 | except request.HTTPError as error: 30 | code = error.code 31 | 32 | self.assertEqual(response.headers['content-type'], 'image/webp', "Expected webp as I can handle a webp") 33 | 34 | if __name__ == '__main__': 35 | baseurl = 'http://localhost:9001' 36 | os.environ["baseurl"] = baseurl 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /tests/TestRDFXML.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | import os 4 | import sys 5 | import requests 6 | try: 7 | from urllib.request import urlopen 8 | except ImportError: 9 | from urllib2 import urlopen 10 | from urllib import request 11 | 12 | 13 | class TestRDFXML(unittest.TestCase): 14 | baseurl = '' 15 | def setUp(self): 16 | self.baseurl = os.environ["baseurl"] 17 | 18 | def checkRedirect(self, source, target, host): 19 | url = '%s/%s' % (self.baseurl, 'api/presentation/2/ontology.xml') 20 | response=urlopen(url) 21 | header=response.info().get('Content-Type') 22 | self.assertEqual(header, 'application/rdf+xml', 'ontology.xml returned Content-Type %s not application/rdf+xml.' % header) 23 | 24 | def test_jsonldmimetype(self): 25 | url = '%s/%s' % (self.baseurl, 'api/image/2#') 26 | opener = request.build_opener() 27 | opener.addheaders = [('Accept', 'application/rdf+xml')] 28 | response=opener.open(url) 29 | location=response.geturl() 30 | self.assertEqual(location, 'https://iiif.io/api/image/2/ontology.xml', 'Failed to redirect with accept') 31 | 32 | # Currently forwarding all requests 33 | #response=urlopen(url) 34 | #self.assertEqual(response.geturl(), 'https://iiif.io/api/image/2.1/', 'Failed to correctly redirect without accept') 35 | 36 | if __name__ == '__main__': 37 | baseurl = 'http://localhost:9001' 38 | if len(sys.argv) == 2: 39 | baseurl = sys.argv[1] 40 | 41 | os.environ["baseurl"] = baseurl 42 | 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /tests/TestHttps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import unittest 3 | import os 4 | import requests 5 | 6 | class TestHttps(unittest.TestCase): 7 | baseurl = '' 8 | def setUp(self): 9 | self.baseurl = os.environ["baseurl"] 10 | 11 | def test_redirect(self): 12 | url = "%s/%s" % (self.baseurl, 'index.html') 13 | 14 | headers = {'cloudFront-forwarded-proto': 'http'} 15 | response = requests.get(url, headers=headers, allow_redirects=False) 16 | code = response.status_code 17 | self.assertEqual(code,301, 'Failed to redirect from http to https got code %s from URL %s' % (code, url)) 18 | 19 | location=response.headers['Location'] 20 | self.assertEqual(location,"https://iiif.io/index.html", 'Failed to redirect to correct place. Expected to go to https://iiif.io but was forwarded to %s' % (location)) 21 | 22 | # Check CORS headers 23 | self.assertTrue('Access-Control-Allow-Origin' in response.headers, 'Missing Access-Control-Allow-Origin header from %s' % location) 24 | self.assertEqual(response.headers['Access-Control-Allow-Origin'],"*", 'Expected header Access-Control-Allow-Origin:* but was Access-Control-Allow-Origin:%s' % (response.headers['Access-Control-Allow-Origin'])) 25 | 26 | def test_noredirect(self): 27 | url = self.baseurl 28 | headers = {'CloudFront-Forwarded-Proto': 'https'} 29 | response = requests.get(url, headers=headers, allow_redirects=False) 30 | 31 | code = response.status_code 32 | self.assertEqual(code,200, 'Failed expected 200 but got code %s for https page: %s' % (code, url)) 33 | 34 | if __name__ == '__main__': 35 | os.environ["baseurl"] = 'http://localhost:9001' 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /docker-files/nginx.conf: -------------------------------------------------------------------------------- 1 | # Elastic Beanstalk Nginx Configuration File 2 | 3 | user nginx; 4 | error_log /var/log/nginx/error.log debug; 5 | pid /var/run/nginx.pid; 6 | worker_processes auto; 7 | worker_rlimit_nofile 67524; 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | http { 14 | include /etc/nginx/mime.types; 15 | default_type application/octet-stream; 16 | 17 | log_format upstreamlog '[$time_local] $remote_addr - code: $status - $remote_user - $server_name proxying: $upstream_http_location $upstream_addr$uri $request upstream_response_time $upstream_response_time msec $msec request_time $request_time - response: $upstream_status, cache: $upstream_cache_status'; 18 | 19 | #log_format main 'test $remote_addr - $remote_user [$time_local] "$request" ' 20 | # 'code: $status $body_bytes_sent "$http_referer" ' 21 | # '"$http_user_agent" "$http_x_forwarded_for"'; 22 | 23 | include conf.d/*.conf; 24 | 25 | map $http_upgrade $connection_upgrade { 26 | default "upgrade"; 27 | } 28 | 29 | server { 30 | listen 80 default_server; 31 | access_log /var/log/nginx/access.log upstreamlog; 32 | 33 | client_header_timeout 60; 34 | client_body_timeout 60; 35 | keepalive_timeout 60; 36 | gzip off; 37 | gzip_comp_level 4; 38 | gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; 39 | 40 | 41 | # Include the Elastic Beanstalk generated locations 42 | include conf.d/elasticbeanstalk/*.conf; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/TestValidators.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | import os 4 | from urllib.request import urlopen 5 | from urllib import request 6 | import requests 7 | 8 | class TestValidators(unittest.TestCase): 9 | baseurl = '' 10 | def setUp(self): 11 | self.baseurl = os.environ["baseurl"] 12 | 13 | def test_imagevalidator(self): 14 | url = '%s/%s' % (self.baseurl, 'api/image/validator/service/list_tests') 15 | code = 0 16 | try: 17 | response = requests.get(url, allow_redirects=False) 18 | code = response.status_code 19 | except request.HTTPError as error: 20 | code = error.code 21 | 22 | self.assertEqual(code, 302, 'Problem retriving the image validator got: %s from %s' % (code, url)) 23 | 24 | if 'Location' in response.headers: 25 | location = response.headers['Location'] 26 | 27 | self.assertEqual(location, 'https://image-validator.iiif.io/list_tests', "Redirect target incorrect") 28 | ## TODO test webp 29 | 30 | def test_api(self): 31 | url = '%s/%s' % (self.baseurl, 'api/presentation/validator/service/validate') 32 | code = 0 33 | try: 34 | response = requests.get(url, allow_redirects=False) 35 | code = response.status_code 36 | except request.HTTPError as error: 37 | code = error.code 38 | 39 | self.assertEqual(code,302, 'Problem retriving the presentation validator got: %s from %s' % (code, url)) 40 | 41 | if 'Location' in response.headers: 42 | location = response.headers['Location'] 43 | 44 | self.assertEqual(location, 'https://presentation-validator.iiif.io/validate', "Redirect target incorrect") 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /tests/TestPrezi3.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | import unittest 3 | import os 4 | import sys 5 | import requests 6 | 7 | class TestPrezi3(unittest.TestCase): 8 | baseurl = '' 9 | desturl = '' 10 | def setUp(self): 11 | self.baseurl = os.environ["baseurl"].replace('localhost','0.0.0.0') 12 | self.desturl = os.environ["desturl"].replace('localhost','0.0.0.0') 13 | 14 | def checkOK(self, source, host): 15 | code = 0 16 | response = requests.get(source, allow_redirects=False, headers={'host': host}) 17 | code = response.status_code 18 | self.assertEqual(code, 200, 'Failed to get 200 from host %s due to %s' % (host, code)) 19 | 20 | def redirectCheck(self, url, target): 21 | code = 0 22 | response = requests.get(url, allow_redirects=False, headers={'host': 'prezi3.iiif.io'}) 23 | code = response.status_code 24 | location = url 25 | if 'Location' in response.headers: 26 | location = response.headers['Location'] 27 | self.assertEqual(code, 301, 'Failed to get redirected to %s due to %s' % (url, code)) 28 | self.assertEqual(location, target, 'Failed to redirect to the correct place. Expected %s but got %s' % (target, location)) 29 | 30 | def test_prezi3(self): 31 | url = '%s/%s' % (self.baseurl, 'api/presentation/3.0/') 32 | target = 'http://iiif.io/api/presentation/3.0/' 33 | self.redirectCheck(url, target) 34 | 35 | def test_apiredirect(self): 36 | url = '%s/%s' % (self.baseurl, '') 37 | target = 'http://iiif.io/' 38 | self.redirectCheck(url, target) 39 | 40 | def test_presentationMissingslash(self): 41 | url = '%s/%s' % (self.baseurl, 'api/presentation/3.0') 42 | target = 'http://iiif.io/api/presentation/3.0' 43 | self.redirectCheck(url, target) 44 | 45 | if __name__ == '__main__': 46 | baseurl = 'http://localhost:5000' 47 | if len(sys.argv) == 2: 48 | baseurl = sys.argv[1] 49 | 50 | os.environ["baseurl"] = baseurl 51 | os.environ["desturl"] = baseurl 52 | 53 | 54 | unittest.main() 55 | -------------------------------------------------------------------------------- /tests/TestDomainNames.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import sys 4 | import requests 5 | 6 | class TestDomainNames(unittest.TestCase): 7 | baseurl = '' 8 | desturl = '' 9 | def setUp(self): 10 | self.baseurl = os.environ["baseurl"].replace('localhost','0.0.0.0') 11 | self.desturl = os.environ["desturl"].replace('localhost','0.0.0.0') 12 | 13 | def checkOK(self, source, host): 14 | code = 0 15 | response = requests.get(source, allow_redirects=False, headers={'host': host}) 16 | code = response.status_code 17 | self.assertEqual(code, 200, 'Failed to get 200 from host %s due to %s' % (host, code)) 18 | 19 | def redirectCheck(self, url, target, host): 20 | code = 0 21 | response = requests.get(url, allow_redirects=False, headers={'host': host}) 22 | code = response.status_code 23 | location = url 24 | if 'Location' in response.headers: 25 | location = response.headers['Location'] 26 | 27 | self.assertEqual(code, 301, 'Failed to get redirected to %s due to %s' % (url, code)) 28 | self.assertEqual(location, target, 'Failed to redirect to the correct place. Expected %s but got %s' % (target, location)) 29 | 30 | def runShowcaseCheck(self, host): 31 | url = '%s/%s' % (self.baseurl, '') 32 | target = 'https://iiif.io/demos/' 33 | self.redirectCheck(url, target, host) 34 | 35 | url = '%s/%s' % (self.baseurl, '/showcase/osd-viewer/') 36 | target = 'https://iiif.io/demos/' 37 | self.redirectCheck(url, target, host) 38 | 39 | 40 | def test_showcase(self): 41 | self.runShowcaseCheck('showcase.iiif.io') 42 | 43 | def test_demo(self): 44 | self.runShowcaseCheck('demo.iiif.io') 45 | 46 | def test_demos(self): 47 | self.runShowcaseCheck('demos.iiif.io') 48 | 49 | if __name__ == '__main__': 50 | baseurl = 'http://localhost:9001' 51 | if len(sys.argv) == 2: 52 | baseurl = sys.argv[1] 53 | 54 | os.environ["baseurl"] = baseurl 55 | os.environ["desturl"] = baseurl 56 | 57 | unittest.main() 58 | -------------------------------------------------------------------------------- /tests/TestSuite.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | import unittest 3 | import TestJsonLD 4 | import TestProxy 5 | import TestRedirect 6 | import TestComingsoon 7 | import TestRDFXML 8 | import TestValidators 9 | import TestIE 10 | import TestPrezi3 11 | import TestImageAPI 12 | import TestHttps 13 | import TestCORS 14 | import TestsFileSwitch 15 | import TestSharedCanvas 16 | import TestDomainNames 17 | import os 18 | import sys 19 | 20 | def suite(): 21 | tests = [] 22 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestJsonLD.TestJsonLD)) 23 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestProxy.TestProxy)) 24 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestRedirect.TestRedirect)) 25 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestValidators.TestValidators)) 26 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestIE.TestIE)) 27 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestRDFXML.TestRDFXML)) 28 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestPrezi3.TestPrezi3)) 29 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestHttps.TestHttps)) 30 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestImageAPI.TestImageAPI)) 31 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestCORS.TestCORS)) 32 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestsFileSwitch.TestFileSwitch)) 33 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestSharedCanvas.TestSharedCanvas)) 34 | tests.append(unittest.TestLoader().loadTestsFromTestCase(TestDomainNames.TestDomainNames)) 35 | return unittest.TestSuite(tests) 36 | 37 | if __name__ == '__main__': 38 | baseurl = 'http://localhost:9001' 39 | desturl = baseurl 40 | if len(sys.argv) > 1: 41 | baseurl = sys.argv[1] 42 | desturl = baseurl 43 | if len(sys.argv) > 2: 44 | desturl = sys.argv[2] 45 | 46 | os.environ["baseurl"] = baseurl 47 | os.environ["desturl"] = desturl 48 | 49 | mySuit=suite() 50 | 51 | runner=unittest.TextTestRunner() 52 | result = runner.run(mySuit) 53 | 54 | if result.wasSuccessful(): 55 | sys.exit(0) 56 | else: 57 | sys.exit(1) 58 | 59 | -------------------------------------------------------------------------------- /tests/TestImageAPI.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | import unittest 3 | import os 4 | import sys 5 | import requests 6 | import json 7 | 8 | class TestImageAPI(unittest.TestCase): 9 | baseurl = '' 10 | desturl = '' 11 | 12 | def setUp(self): 13 | self.baseurl = os.environ["baseurl"].replace('localhost','0.0.0.0') 14 | self.desturl = os.environ["desturl"].replace('localhost','0.0.0.0') 15 | 16 | def isValidJson(self, url): 17 | try: 18 | result = requests.get(url) 19 | result.json() 20 | self.assertEqual(result.status_code, 200, "Non 200 return code from %s" % url) 21 | except ValueError as error: 22 | self.assertTrue(False, "Invalid json from %s" % url) 23 | except requests.exceptions.ConnectionError as ConnectError: 24 | self.assertTrue(False, "Unable to connect to %s" % url) 25 | 26 | def test_10(self): 27 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.0/example/reference/detail/info.json')) 28 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.0/example/reference/67352ccc-d1b0-11e1-89ae-279075081939/info.json')) 29 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.0/example/reference/page1-full/info.json')) 30 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.0/example/reference/page2-full/info.json')) 31 | 32 | def test_11(self): 33 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.1/example/reference/detail/info.json')) 34 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.1/example/reference/67352ccc-d1b0-11e1-89ae-279075081939/info.json')) 35 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.1/example/reference/page1-full/info.json')) 36 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/1.1/example/reference/page2-full/info.json')) 37 | 38 | def test_20(self): 39 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.0/example/reference/detail/info.json')) 40 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.0/example/reference/67352ccc-d1b0-11e1-89ae-279075081939/info.json')) 41 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.0/example/reference/page1-full/info.json')) 42 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.0/example/reference/page2-full/info.json')) 43 | 44 | def test_21(self): 45 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.1/example/reference/detail/info.json')) 46 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.1/example/reference/67352ccc-d1b0-11e1-89ae-279075081939/info.json')) 47 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.1/example/reference/page1-full/info.json')) 48 | self.isValidJson('%s/%s' % (self.baseurl, 'api/image/2.1/example/reference/page2-full/info.json')) 49 | 50 | if __name__ == '__main__': 51 | baseurl = 'http://localhost:5000' 52 | if len(sys.argv) == 2: 53 | baseurl = sys.argv[1] 54 | 55 | os.environ["baseurl"] = baseurl 56 | os.environ["desturl"] = baseurl 57 | 58 | 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /tests/TestJsonLD.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | try: 4 | from urllib.request import urlopen 5 | except ImportError: 6 | from urllib2 import urlopen 7 | from urllib import request 8 | import os 9 | import json 10 | 11 | class TestJsonLD(unittest.TestCase): 12 | baseurl = '' 13 | def setUp(self): 14 | self.baseurl = os.environ["baseurl"] 15 | 16 | def test_mimetype(self): 17 | url = '%s/%s' % (self.baseurl, 'api/image/2/context.json') 18 | response=urlopen(url) 19 | mimetype=response.info().get('Content-type') 20 | self.assertEqual(mimetype, 'application/json', 'Mimetype should be json if I dont support jsonld') 21 | 22 | def test_jsonldmimetype(self): 23 | url = '%s/%s' % (self.baseurl, 'api/image/2/context.json') 24 | jsonldmimetype='application/ld+json' 25 | opener = request.build_opener() 26 | opener.addheaders = [('Accept', jsonldmimetype)] 27 | response=opener.open(url) 28 | mimetype=response.info().get('Content-type') 29 | self.assertEqual(mimetype, 'application/ld+json', 'Mimetype should be jsonld if I support jsonld') 30 | 31 | def test_cookbook_manifest(self): 32 | url = '%s/%s' % (self.baseurl, 'api/cookbook/recipe/0057-publishing-v2-and-v3/manifest.json') 33 | with urlopen(url) as urlPointer: 34 | content_type = urlPointer.getheader('Content-Type') 35 | self.assertEqual(content_type, "application/ld+json;profile=http://iiif.io/api/presentation/3/context.json", "Response should give the IIIF version") 36 | 37 | cors = urlPointer.getheader('access-control-allow-origin') 38 | #self.assertEqual(cors, "*", "Cors header set incorrectly") 39 | 40 | manifest = json.loads(urlPointer.read().decode()) 41 | self.assertEqual(manifest['@context'], 'http://iiif.io/api/presentation/3/context.json', 'Expected default retrieval of manifest to be version 3') 42 | 43 | opener = request.build_opener() 44 | opener.addheaders = [('Accept', "application/ld+json;profile=http://iiif.io/api/presentation/3/context.json")] 45 | with opener.open(url) as urlPointer: 46 | content_type = urlPointer.getheader('Content-Type') 47 | self.assertEqual(content_type, "application/ld+json;profile=http://iiif.io/api/presentation/3/context.json", "Response should give the IIIF version") 48 | 49 | cors = urlPointer.getheader('access-control-allow-origin') 50 | #self.assertEqual(cors, "*", "Cors header set incorrectly") 51 | 52 | manifest = json.loads(urlPointer.read().decode()) 53 | self.assertEqual(manifest['@context'], 'http://iiif.io/api/presentation/3/context.json', 'Passing the 3 accept header should get version 3 but got version 2') 54 | 55 | opener = request.build_opener() 56 | opener.addheaders = [('Accept', "application/ld+json;profile=http://iiif.io/api/presentation/2/context.json")] 57 | with opener.open(url) as urlPointer: 58 | content_type = urlPointer.getheader('Content-Type') 59 | self.assertEqual(content_type, "application/ld+json;profile=http://iiif.io/api/presentation/2/context.json", "Response should give the IIIF version") 60 | 61 | cors = urlPointer.getheader('access-control-allow-origin') 62 | #self.assertEqual(cors, "*", "Cors header set incorrectly") 63 | 64 | manifest = json.loads(urlPointer.read().decode()) 65 | self.assertEqual(manifest['@context'], 'http://iiif.io/api/presentation/2/context.json', 'Passing the 2 accept header should get version 2 manifest') 66 | 67 | 68 | if __name__ == '__main__': 69 | unittest.main() 70 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | Welcome 15 | 85 | 86 | 87 |
88 |

Congratulations

89 |

Your first AWS Elastic Beanstalk Application is now running on your own dedicated environment in the AWS Cloud

90 |
91 | 92 |
93 |

What's Next?

94 | 100 |

Related Links

101 | 104 |
105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /tests/TestCORS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import unittest 3 | import os 4 | import requests 5 | 6 | class TestCORS(unittest.TestCase): 7 | baseurl = '' 8 | def setUp(self): 9 | self.baseurl = os.environ["baseurl"] 10 | 11 | def test_options_cors(self): 12 | url = "%s/%s" % (self.baseurl,'api/cookbook/recipe/0068-newspaper/newspaper_issue_1-manifest.json') 13 | headers = { 14 | "Origin": "https://example.com", 15 | "Accept": "*/*", 16 | "Accept-Encoding": "gzip, deflate, br", 17 | "Connection": "keep-alive", 18 | "User-Agent": "HTTPie/3.2.1" 19 | } 20 | 21 | response = requests.options(url, allow_redirects=False, headers=headers) 22 | code = response.status_code 23 | self.assertEqual(code,204, 'Failed to get newspaper json file for CORS testing. Got response %s from URL %s\n%s' % (code, url, response.text)) 24 | 25 | # Check CORS headers 26 | self.assertTrue('Access-Control-Allow-Origin' in response.headers, 'Missing Access-Control-Allow-Origin header from %s' % url) 27 | self.assertEqual(response.headers['Access-Control-Allow-Origin'],"*", 'Expected header Access-Control-Allow-Origin:* but was Access-Control-Allow-Origin:%s' % (response.headers['Access-Control-Allow-Origin'])) 28 | 29 | def test_xml_cors(self): 30 | url = "%s/%s" % (self.baseurl, 'api/cookbook/recipe/0068-newspaper/newspaper_issue_1-alto_p1.xml') 31 | 32 | response = requests.get(url, allow_redirects=False) 33 | code = response.status_code 34 | self.assertEqual(code,200, 'Failed to get required xml file for CORS testing. Got response %s from URL %s' % (code, url)) 35 | 36 | # Check CORS headers 37 | self.assertTrue('Access-Control-Allow-Origin' in response.headers, 'Missing Access-Control-Allow-Origin header from %s' % url) 38 | self.assertEqual(response.headers['Access-Control-Allow-Origin'],"*", 'Expected header Access-Control-Allow-Origin:* but was Access-Control-Allow-Origin:%s' % (response.headers['Access-Control-Allow-Origin'])) 39 | 40 | self.assertEqual(response.headers['Content-Type'],"text/xml", 'Expected header Content-Type: text/xml but was Content-Type: %s' % (response.headers['Content-Type'])) 41 | 42 | def test_vtt_cors(self): 43 | url = "%s/%s" % (self.baseurl, 'api/cookbook/recipe/0074-multiple-language-captions/Per_voi_signore_Modelli_francesi_en.vtt') 44 | 45 | response = requests.get(url, allow_redirects=False) 46 | code = response.status_code 47 | self.assertEqual(code,200, 'Failed to get required vtt file for CORS testing. Got response %s from URL %s' % (code, url)) 48 | 49 | # Check CORS headers 50 | self.assertTrue('Access-Control-Allow-Origin' in response.headers, 'Missing Access-Control-Allow-Origin header from %s' % url) 51 | self.assertEqual(response.headers['Access-Control-Allow-Origin'],"*", 'Expected header Access-Control-Allow-Origin:* but was Access-Control-Allow-Origin:%s' % (response.headers['Access-Control-Allow-Origin'])) 52 | 53 | self.assertEqual(response.headers['Content-Type'],"text/vtt", 'Expected header Content-Type: text/vtt but was Content-Type: %s' % (response.headers['Content-Type'])) 54 | 55 | def test_single_cors(self): 56 | url = "%s/%s" % (self.baseurl, 'api/cookbook/recipe/0003-mvm-video/manifest.json') 57 | 58 | response = requests.get(url, allow_redirects=False) 59 | code = response.status_code 60 | self.assertEqual(code,200, 'Failed to get required json file for CORS testing. Got response %s from URL %s' % (code, url)) 61 | 62 | # Check CORS headers 63 | count = 0 64 | for header in response.headers.keys(): 65 | if header == 'Access-Control-Allow-Origin': 66 | count += 1 67 | 68 | self.assertTrue('Access-Control-Allow-Origin' in response.headers, 'Missing Access-Control-Allow-Origin header from %s' % url) 69 | self.assertEqual(response.headers['Access-Control-Allow-Origin'],"*", 'Expected header Access-Control-Allow-Origin:* but was Access-Control-Allow-Origin:%s' % (response.headers['Access-Control-Allow-Origin'])) 70 | 71 | def test_othercors(self): 72 | url = "%s/%s" % (self.baseurl, 'api/cookbook/recipe/0009-book-1/manifest.json') 73 | 74 | response = requests.get(url, allow_redirects=False) 75 | code = response.status_code 76 | self.assertEqual(code,200, 'Failed to get required json file for CORS testing. Got response %s from URL %s' % (code, url)) 77 | 78 | # Check CORS headers 79 | count = 0 80 | for header in response.headers.keys(): 81 | if header == 'Access-Control-Allow-Origin': 82 | count += 1 83 | 84 | self.assertTrue('Access-Control-Allow-Origin' in response.headers, 'Missing Access-Control-Allow-Origin header from %s' % url) 85 | self.assertEqual(response.headers['Access-Control-Allow-Origin'],"*", 'Expected header Access-Control-Allow-Origin:* but was Access-Control-Allow-Origin:%s' % (response.headers['Access-Control-Allow-Origin'])) 86 | 87 | 88 | 89 | if __name__ == '__main__': 90 | os.environ["baseurl"] = 'http://localhost:9001' 91 | unittest.main() 92 | -------------------------------------------------------------------------------- /tests/TestRedirect.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.5 2 | import unittest 3 | import os 4 | import sys 5 | import requests 6 | try: 7 | import urlparse 8 | except: 9 | from urllib.parse import urlparse 10 | 11 | class TestRedirect(unittest.TestCase): 12 | baseurl = '' 13 | desturl = '' 14 | def setUp(self): 15 | self.baseurl = os.environ["baseurl"] 16 | self.desturl = os.environ["desturl"] 17 | 18 | def checkRedirect(self, source, target, enforceHost=False, target_code=302): 19 | code = 0 20 | response = requests.get(source, allow_redirects=False) 21 | code = response.status_code 22 | location = source 23 | if 'Location' in response.headers: 24 | location = response.headers['Location'] 25 | # print(code, location) 26 | self.assertEqual(code, target_code, 'Failed to get correct code redirected to %s from %s, recieved code: %s' % (target, source, code)) 27 | locationPath = urlparse(location).path 28 | targetPath = urlparse(target).path 29 | self.assertEqual(locationPath, targetPath, 'Failed to redirect to the correct place. Expected %s but got %s' % (targetPath, locationPath)) 30 | if enforceHost: 31 | sourceHost=urlparse(location).hostname 32 | targetHost=urlparse(target).hostname 33 | self.assertEqual(sourceHost, targetHost, 'Failed to redirect to the correct host. Expected %s but got %s' % (targetHost,sourceHost)) 34 | sourceScheme = urlparse(location).scheme 35 | targetScheme = urlparse(target).scheme 36 | self.assertEqual(sourceScheme, targetScheme, 'Failed to redirect using the correct protocol.') 37 | 38 | 39 | def test_api(self): 40 | url = '%s/%s' % (self.baseurl, 'api') 41 | dest = '%s/%s' % ('https://iiif.io', 'api/index.html') 42 | self.checkRedirect(url, dest, True) 43 | 44 | def test_image(self): 45 | url = '%s/%s' % (self.baseurl, 'api/image/') 46 | dest = '%s/%s' % (self.desturl, 'api/image/3.0/') 47 | self.checkRedirect(url, dest) 48 | 49 | def test_presentation(self): 50 | url = '%s/%s' % (self.baseurl, 'api/presentation/index.html') 51 | dest = '%s/%s' % (self.desturl, 'api/presentation/3.0/') 52 | self.checkRedirect(url, dest) 53 | def test_validator(self): 54 | url = '%s/%s' % (self.baseurl, 'api/presentation/validator') 55 | dest = '%s/%s' % (self.desturl, 'api/presentation/validator/service') 56 | self.checkRedirect(url, dest) 57 | # why is this here? 58 | def test_ontology(self): 59 | url = '%s/%s' % (self.baseurl, 'api/presentation/2') 60 | dest = '%s/%s' % (self.desturl, 'api/presentation/2/ontology.xml') 61 | self.checkRedirect(url, dest) 62 | def test_metadata(self): 63 | url = '%s/%s' % (self.baseurl, 'api/metadata') 64 | dest = '%s/%s' % (self.desturl, 'api/presentation/2.1/') 65 | self.checkRedirect(url, dest) 66 | def test_presentation1(self): 67 | url = '%s/%s' % (self.baseurl, '/api/presentation/1.0') 68 | dest = '%s/%s' % (self.desturl, 'api/presentation/2.1/') 69 | self.checkRedirect(url, dest) 70 | def test_auth(self): 71 | url = '%s/%s' % (self.baseurl, '/api/auth/') 72 | dest = '%s/%s' % (self.desturl, 'api/auth/2.0/') 73 | self.checkRedirect(url, dest) 74 | def test_auth0(self): 75 | url = '%s/%s' % (self.baseurl, '/api/auth/0/') 76 | dest = '%s/%s' % (self.desturl, 'api/auth/1.0/') 77 | self.checkRedirect(url, dest) 78 | def test_search(self): 79 | url = '%s/%s' % (self.baseurl, '/api/search') 80 | dest = '%s/%s' % (self.desturl, 'api/search/2.0/') 81 | self.checkRedirect(url, dest) 82 | def test_api_redirect(self): 83 | url = '%s/%s' % (self.baseurl, 'api/image/') 84 | dest = '%s/%s' % ('https://iiif.io', 'api/image/3.0/') 85 | self.checkRedirect(url, dest, True) 86 | 87 | def test_editor_policy(self): 88 | url = '%s/%s' % (self.baseurl, 'api/annex/notes/editors/') 89 | dest = '%s/%s' % (self.desturl, 'community/policy/editorial/') 90 | self.checkRedirect(url, dest) 91 | 92 | def test_editor_policy_index(self): 93 | url = '%s/%s' % (self.baseurl, 'api/annex/notes/editors/index.html') 94 | dest = '%s/%s' % (self.desturl, 'community/policy/editorial/') 95 | self.checkRedirect(url, dest) 96 | 97 | # def test_slash404(self): 98 | # url = '%s/%s' % (self.baseurl, '/404.html') 99 | # dest = '%s/%s' % ('https://iiif.io', '/404.html') 100 | # self.checkRedirect(url, dest, True) 101 | 102 | def test_404(self): 103 | url = '%s/%s' % (self.baseurl, '/estste.html') 104 | dest = '%s/%s' % ('https://iiif.io', '/404.html') 105 | self.checkRedirect(url, dest, True, target_code=301) 106 | 107 | def test_nested404(self): 108 | url = '%s/%s' % (self.baseurl, '/estste/setestse') 109 | dest = '%s/%s' % ('https://iiif.io', '/404.html') 110 | self.checkRedirect(url, dest, True, target_code=301) 111 | 112 | # 2021 Website move shared-canvas now in the api directory 113 | def test_sharedCanvas(self): 114 | url = '%s/%s' % (self.baseurl, 'model/shared-canvas/1.0/') 115 | dest = '%s/%s' % ('https://iiif.io', 'api/model/shared-canvas/1.0/') 116 | self.checkRedirect(url, dest, True, target_code=301) 117 | 118 | # 2021 Website IIIF logo moved 119 | def test_iiiflogo(self): 120 | url = '%s/%s' % (self.baseurl, 'img/logo-iiif-34x30.png') 121 | dest = '%s/%s' % ('https://iiif.io', 'assets/uploads/logos/logo-iiif-34x30.png') 122 | self.checkRedirect(url, dest, True, target_code=302) 123 | 124 | 125 | if __name__ == '__main__': 126 | baseurl = 'http://localhost:5000' 127 | if len(sys.argv) == 2: 128 | baseurl = sys.argv[1] 129 | 130 | os.environ["baseurl"] = baseurl 131 | unittest.main() 132 | -------------------------------------------------------------------------------- /.platform/nginx/conf.d/elasticbeanstalk/00_application.conf: -------------------------------------------------------------------------------- 1 | # do www.iiif.io rediect 2 | 3 | add_header 'Access-Control-Allow-Origin' '*'; 4 | if ($http_cloudFront_forwarded_proto = "http") { 5 | return 301 https://iiif.io$request_uri; 6 | } 7 | 8 | #include conf.d/elasticbeanstalk/*.conf; 9 | location '/get-started/training/outreach-materials/ ' { 10 | rewrite ^ 'https://iiif.io/get-started/training/outreach-materials/' permanent; 11 | } 12 | 13 | rewrite ^/api/image(/|/index.html)?$ https://iiif.io/api/image/3.0/ redirect; 14 | rewrite ^/api/presentation(/|/index.html)?$ https://iiif.io/api/presentation/3.0/ redirect; 15 | rewrite ^/api$ https://iiif.io/api/index.html redirect; 16 | 17 | rewrite /api/presentation/validator[/]?$ https://iiif.io/api/presentation/validator/service redirect; 18 | 19 | rewrite /api/presentation/2$ https://iiif.io/api/presentation/2/ontology.xml redirect; 20 | rewrite /api/image/2$ https://iiif.io/api/image/2/ontology.xml redirect; 21 | rewrite /api/metadata(/|/index.html)?$ https://iiif.io/api/presentation/2.1/ redirect; 22 | rewrite /api/presentation/1.0(/|/index.html)?$ https://iiif.io/api/presentation/2.1/ redirect; 23 | rewrite /api/auth(/|/index.html)?$ https://iiif.io/api/auth/2.0/ redirect; 24 | rewrite /api/auth/0(/|/index.html)?$ https://iiif.io/api/auth/1.0/ redirect; 25 | rewrite /api/search(/|/index.html|/0|/0/|/0/index.html)?$ https://iiif.io/api/search/2.0/ redirect; 26 | rewrite /api/annex/notes/editors(/|/index.html)?$ https://iiif.io/community/policy/editorial/ redirect; 27 | 28 | rewrite /api/image/validator/service(.*)$ https://image-validator.iiif.io$1 redirect; 29 | rewrite /api/presentation/validator/service(.*)$ https://presentation-validator.iiif.io$1 redirect; 30 | #rewrite /\/404.html https://iiif.io/404.html redirect; 31 | 32 | rewrite ^/model/shared-canvas(.*)$ https://iiif.io/api/model/shared-canvas$1 permanent; 33 | rewrite /img/logo-iiif-34x30.png$ https://iiif.io/assets/uploads/logos/logo-iiif-34x30.png redirect; 34 | 35 | 36 | #rewrite /api/image/.*/example/.*$ https://iiif.io/comingsoon/ redirect; 37 | 38 | # https://msdn.microsoft.com/en-us/library/cc817573.aspx 39 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 40 | 41 | location /api/image/3.0/example { 42 | include conf.d/elasticbeanstalk/subfiles/image-api.conf; 43 | } 44 | location /api/image/2.1/example { 45 | include conf.d/elasticbeanstalk/subfiles/image-api.conf; 46 | } 47 | location /api/image/2.0/example { 48 | include conf.d/elasticbeanstalk/subfiles/image-api.conf; 49 | } 50 | location /api/image/1.1/example { 51 | include conf.d/elasticbeanstalk/subfiles/image-api.conf; 52 | } 53 | location /api/image/1.0/example { 54 | include conf.d/elasticbeanstalk/subfiles/image-api.conf; 55 | } 56 | 57 | location /assets/images/heroes { 58 | add_header Vary Accept; 59 | proxy_pass http://iiif-website.s3-website-us-east-1.amazonaws.com$image$webp_suffix; 60 | proxy_hide_header Content-Type; 61 | add_header 'Content-Type' 'image/$webp_format'; 62 | } 63 | 64 | location / { 65 | location / { 66 | include conf.d/elasticbeanstalk/subfiles/iiif-website.conf; 67 | add_header 'Cache-Control' 'public, no-transform, max-age=300'; 68 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 69 | } 70 | location ~ \.json$ { 71 | include conf.d/elasticbeanstalk/subfiles/iiif-website.conf; 72 | add_header 'Access-Control-Allow-Origin' '*'; 73 | add_header 'Cache-Control' 'public, no-transform, max-age=300'; 74 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 75 | } 76 | } 77 | 78 | location /api/cookbook/recipe/0057-publishing-v2-and-v3/manifest.json { 79 | resolver 8.8.8.8; 80 | proxy_ssl_verify off; 81 | proxy_ssl_server_name on; 82 | proxy_set_header Host 'preview.iiif.io'; 83 | proxy_hide_header x-amz-id-2; 84 | proxy_hide_header x-amz-request-id; 85 | proxy_intercept_errors on; 86 | proxy_pass https://preview.iiif.io:443/cookbook/0057-conneg/recipe/0057-publishing-v2-and-v3/manifest-v$version.json; 87 | # add_header 'Access-Control-Allow-Origin' '*'; 88 | proxy_hide_header 'Content-Type'; 89 | add_header 'Cache-Control' 'public, no-transform, max-age=300'; 90 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 91 | add_header 'Content-Type' "application/ld+json;profile=http://iiif.io/api/presentation/$version/context.json"; 92 | } 93 | 94 | location ^~ /api/ { 95 | # do json to json ld mime type conversion 96 | # do presentation service 97 | location /api/ { 98 | include conf.d/elasticbeanstalk/subfiles/iiif-website.conf; 99 | add_header 'Cache-Control' 'public, no-transform, max-age=300'; 100 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 101 | } 102 | location ~ \.json$ { 103 | include conf.d/elasticbeanstalk/subfiles/iiif-website.conf; 104 | proxy_hide_header 'Content-Type'; 105 | add_header 'Content-Type' '$jsonmimetype'; 106 | add_header 'Cache-Control' 'public, no-transform, max-age=300'; 107 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 108 | add_header 'Access-Control-Allow-Origin' '*'; 109 | } 110 | location ~ ontology\.xml$ { 111 | include conf.d/elasticbeanstalk/subfiles/iiif-website.conf; 112 | proxy_hide_header 'Content-Type'; 113 | add_header 'Access-Control-Allow-Origin' '*'; 114 | add_header 'Content-Type' '$custom_content_type'; 115 | add_header 'Cache-Control' 'public, no-transform, max-age=2419200'; 116 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 117 | } 118 | location ~ \.xml$ { 119 | include conf.d/elasticbeanstalk/subfiles/iiif-website.conf; 120 | add_header 'Access-Control-Allow-Origin' '*'; 121 | add_header 'Cache-Control' 'public, no-transform, max-age=2419200'; 122 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 123 | } 124 | location ~ \.vtt$ { 125 | include conf.d/elasticbeanstalk/subfiles/iiif-website.conf; 126 | proxy_hide_header 'Content-Type'; 127 | add_header 'Content-Type' 'text/vtt'; 128 | add_header 'Access-Control-Allow-Origin' '*'; 129 | add_header 'Cache-Control' 'public, no-transform, max-age=2419200'; 130 | add_header "X-UA-Compatible" "IE=Edge,chrome=1"; 131 | } 132 | } 133 | location =/apple-touch-icon-precomposed.png { 134 | access_log off; 135 | } 136 | location =/apple-touch-icon.png { 137 | access_log off; 138 | } 139 | location ~ ^/.*.php { 140 | access_log off; 141 | } 142 | location ~ ^/.*wp-admin.* { 143 | access_log off; 144 | } 145 | #showcase? 146 | #shared canvas? 147 | --------------------------------------------------------------------------------