├── 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 |Your first AWS Elastic Beanstalk Application is now running on your own dedicated environment in the AWS Cloud
90 |