Beispiel #1
0
 def do_GET_body(self):
     """Create body of GET."""
     iiif = self.iiif
     if (len(self.path) > 1024):
         raise IIIFError(code=414,
                         text="URI Too Long: Max 1024 chars, got %d\n" %
                         len(self.path))
     try:
         # self.path has leading / then identifier/params...
         self.path = self.path.lstrip('/')
         sys.stderr.write("path = %s" % (self.path))
         iiif.parse_url(self.path)
     except Exception as e:
         # Something completely unexpected => 500
         raise IIIFError(
             code=500,
             text=
             "Internal Server Error: unexpected exception parsing request ("
             + str(e) + ")")
     # Now we have a full iiif request
     if (re.match('[\w\.\-]+$', iiif.identifier)):
         file = os.path.join(TESTIMAGE_DIR, iiif.identifier)
         if (not os.path.isfile(file)):
             images_available = ""
             for image_file in os.listdir(TESTIMAGE_DIR):
                 if (os.path.isfile(os.path.join(TESTIMAGE_DIR,
                                                 image_file))):
                     images_available += "  " + image_file + "\n"
             raise IIIFError(code=404,
                             parameter="identifier",
                             text="Image resource '" + iiif.identifier +
                             "' not found. Local image files available:\n" +
                             images_available)
     else:
         raise IIIFError(
             code=404,
             parameter="identifier",
             text="Image resource '" + iiif.identifier +
             "' not found. Only local test images and http: URIs for images are supported.\n"
         )
     # Now know image is OK
     manipulator = IIIFRequestHandler.manipulator_class()
     # Stash manipulator object so we can cleanup after reading file
     self.manipulator = manipulator
     self.compliance_uri = manipulator.compliance_uri
     if (iiif.info):
         # get size
         manipulator.srcfile = file
         manipulator.do_first()
         # most of info.json comes from config, a few things
         # specific to image
         i = IIIFInfo()
         i.identifier = self.iiif.identifier
         i.width = manipulator.width
         i.height = manipulator.height
         import io
         return (io.StringIO(i.as_json()), "application/json")
     else:
         (outfile, mime_type) = manipulator.derive(file, iiif)
         return (open(outfile, 'r'), mime_type)
Beispiel #2
0
 def image_request_response(self, path):
     """Parse image request and create response."""
     # Parse the request in path
     if (len(path) > 1024):
         raise IIIFError(code=414,
                         text="URI Too Long: Max 1024 chars, got %d\n" %
                         len(path))
     try:
         self.iiif.identifier = self.identifier
         self.iiif.parse_url(path)
     except IIIFRequestPathError as e:
         # Reraise as IIIFError with code=404 because we can't tell
         # whether there was an encoded slash in the identifier or
         # whether there was a bad number of path segments.
         raise IIIFError(code=404, text=e.text)
     except IIIFError as e:
         # Pass through
         raise e
     except Exception as e:
         # Something completely unexpected => 500
         raise IIIFError(
             code=500,
             text=
             "Internal Server Error: unexpected exception parsing request ("
             + str(e) + ")")
     dr = degraded_request(self.identifier)
     if (dr):
         self.logger.info("image_request: degraded %s -> %s" %
                          (self.identifier, dr))
         self.degraded = self.identifier
         self.identifier = dr
         self.iiif.quality = 'gray'
     else:
         # Parsed request OK, attempt to fulfill
         self.logger.info("image_request: %s" % (self.identifier))
     file = self.file
     self.manipulator.srcfile = file
     self.manipulator.do_first()
     if (self.api_version < '2.0' and self.iiif.format is None
             and 'Accept' in request.headers):
         # In 1.0 and 1.1 conneg was specified as an alternative to format, see:
         # http://iiif.io/api/image/1.0/#format
         # http://iiif.io/api/image/1.1/#parameters-format
         formats = {
             'image/jpeg': 'jpg',
             'image/tiff': 'tif',
             'image/png': 'png',
             'image/gif': 'gif',
             'image/jp2': 'jps',
             'application/pdf': 'pdf'
         }
         accept = do_conneg(request.headers['Accept'], list(formats.keys()))
         # Ignore Accept header if not recognized, should this be an error
         # instead?
         if (accept in formats):
             self.iiif.format = formats[accept]
     (outfile, mime_type) = self.manipulator.derive(file, self.iiif)
     # FIXME - find efficient way to serve file with headers
     self.add_compliance_header()
     return send_file(outfile, mimetype=mime_type)
Beispiel #3
0
 def test1(self):
     # Just do the trivial XML test
     ie = IIIFError()
     self.assertEqual( str(ie), '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n<error xmlns="http://library.stanford.edu/iiif/image-api/ns/">\n<parameter>unknown</parameter>\n</error>')
     ie.code='501'
     ie.parameter='size'
     ie.text='Negative size not implemented'
     self.assertEqual( str(ie), '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n<error xmlns="http://library.stanford.edu/iiif/image-api/ns/">\n<parameter>size</parameter>\n<text>Negative size not implemented</text>\n</error>')
Beispiel #4
0
 def test04_image_server_response(self):
     """Test image_server_response."""
     e = IIIFError(headers={'x': 'y'})
     (response, status, headers) = e.image_server_response(
         api_version='1.0')
     self.assertTrue(re.match(r'''<\?xml version''', response))
     self.assertEqual(status, 500)
     self.assertEqual(headers, {'x': 'y', 'Content-Type': 'text/xml'})
     (response, status, headers) = e.image_server_response(
         api_version='2.0')
     self.assertTrue(re.match(r'''IIIF Image Server Error\n''', response))
     self.assertEqual(status, 500)
     self.assertEqual(headers, {'x': 'y', 'Content-Type': 'text/plain'})
Beispiel #5
0
 def test03_txt(self):
     """Test txt output."""
     e = IIIFError()
     msg = 'IIIF Image Server Error\n\nUNKNOWN_ERROR\n\nparameter=unknown\ncode=500\n\n'
     self.assertEqual(e.as_txt(), msg)
     e = IIIFError(headers={'cc': 'dd', 'a': 'b'})
     self.assertEqual(e.as_txt(), msg + 'header a=b\nheader cc=dd\n')
Beispiel #6
0
    def do_GET(self):
        """Implement the HTTP GET method.

        The bulk of this code is wrapped in a big try block and anywhere
        within the code may raise an IIIFError which then results in an
        IIIF error response (section 5 of spec).
        """
        self.compliance_uri = None
        self.iiif = IIIFRequest(baseurl='/')
        try:
            (of, mime_type) = self.do_GET_body()
            if (not of):
                raise IIIFError("Unexpected failure to open result image")
            self.send_response(200, 'OK')
            if (mime_type is not None):
                self.send_header('Content-Type', mime_type)
            self.add_compliance_header()
            self.end_headers()
            while (1):
                buffer = of.read(8192)
                if (not buffer):
                    break
                self.wfile.write(buffer)
            # Now cleanup
            self.manipulator.cleanup()
        except IIIFError as e:
            if (self.debug):
                e.text += "\nRequest parameters:\n" + str(self.iiif)
            self.error_response(e.code, str(e))
        except Exception as ue:
            # Anything else becomes a 500 Internal Server Error
            e = IIIFError(code=500,
                          text="Something went wrong... %s ---- %s.\n" %
                          (str(ue), traceback.format_exc()))
            if (self.debug):
                e.text += "\nRequest parameters:\n" + str(self.iiif)
            self.error_response(e.code, str(e))
Beispiel #7
0
 def send_good_response(self, of, mime_type):
     """ Normal successful response
     """
     if (not of):
         raise IIIFError("Unexpected failure to open result image")
     self.send_response(200)
     if (mime_type is not None):
         self.send_header('Content-Type',mime_type)
     self.add_compliance_header()
     self.add_cors_header()
     self.end_headers()
     while (1):
         buffer = of.read(8192)
         if (not buffer):
             break
         self.wfile.write(buffer)
Beispiel #8
0
 def test27_IIIFHandler_error_response(self):
     """Test IIIFHandler.error_response()."""
     c = Config()
     c.api_version = '2.1'
     c.klass_name = 'dummy'
     c.image_dir = os.path.join(os.path.dirname(__file__), '../testimages')
     c.tile_height = 512
     c.tile_width = 512
     c.scale_factors = [1, 2]
     c.host = 'example.org'
     c.port = 80
     i = IIIFHandler(prefix='p',
                     identifier='starfish',
                     config=c,
                     klass=IIIFManipulator,
                     auth=None)
     environ = WSGI_ENVIRON()
     with self.test_app.request_context(environ):
         resp = i.error_response(IIIFError(999, 'bwaa'))
         self.assertEqual(resp.status_code, 999)
Beispiel #9
0
 def file(self):
     """Filename property for the source image for the current identifier."""
     file = None
     if (self.config.klass_name == 'gen'):
         for ext in ['.py']:
             file = os.path.join(self.config.generator_dir,
                                 self.identifier + ext)
             if (os.path.isfile(file)):
                 return file
     else:
         for ext in ['.jpg', '.png', '.tif']:
             file = os.path.join(self.config.image_dir,
                                 self.identifier + ext)
             if (os.path.isfile(file)):
                 return file
     # failed, show list of available identifiers as error
     available = "\n ".join(identifiers(self.config))
     raise IIIFError(code=404,
                     parameter="identifier",
                     text="Image resource '" + self.identifier +
                     "' not found. Local resources available:" + available +
                     "\n")
Beispiel #10
0
 def test02_xml(self):
     """Test xml output used in Image API 1.0."""
     # Just do the trivial XML test
     e = IIIFError()
     # Encoding value should be capital UTF-8 per
     # http://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncName
     # but in python3 it comes out at utf-8
     xml = re.sub(r'utf-8', 'UTF-8', e.as_xml())
     self.assertEqual(xml,
                      '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n'
                      '<error xmlns="http://library.stanford.edu/iiif/image-api/ns/">\n'
                      '<parameter>unknown</parameter>\n</error>')
     e.code = '501'
     e.parameter = 'size'
     e.text = 'Negative size not implemented'
     xml = re.sub(r'utf-8', 'UTF-8', e.as_xml())
     self.assertEqual(xml,
                      '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n'
                      '<error xmlns="http://library.stanford.edu/iiif/image-api/ns/">\n'
                      '<parameter>size</parameter>\n'
                      '<text>Negative size not implemented</text>\n</error>')
Beispiel #11
0
    def do_GET_body(self):
        iiif=self.iiif
        if (len(self.path)>1024):
            raise IIIFError(code=414,
                            text="URI Too Long: Max 1024 chars, got %d\n" % len(self.path))
        #print "GET " + self.path
        try:
            iiif.parse_url(self.path)
        except IIIFRequestBaseURI as e:
            info_uri = self.server_and_prefix + '/' + urllib.quote(self.iiif.identifier) + '/info.json'
            raise IIIFError(code=303, 
                            headers={'Location': info_uri})
        except IIIFError as e:
            # Pass through
            raise e
        except Exception as e:
            # Something completely unexpected => 500
            raise IIIFError(code=500,
                            text="Internal Server Error: unexpected exception parsing request (" + str(e) + ")")
        # URL path parsed OK, now determine how to handle request
        if (re.match('[\w\.\-]+$',iiif.identifier)):
            file = os.path.join(IIIFRequestHandler.IMAGE_DIR,iiif.identifier)
            if (not os.path.isfile(file)):
                images_available=""
                for image_file in os.listdir(IIIFRequestHandler.IMAGE_DIR):
                    if (os.path.isfile(os.path.join(IIIFRequestHandler.IMAGE_DIR,image_file))):
                        images_available += "  "+image_file+"\n"
                raise IIIFError(code=404,parameter="identifier",
                                text="Image resource '"+iiif.identifier+"' not found. Local image files available:\n" + images_available)
        else:
            raise IIIFError(code=404,parameter="identifier",
                            text="Image resource '"+iiif.identifier+"' not found. Only local test images and http: URIs for images are supported.\n")
        # 
        self.compliance_level=self.manipulator.complianceLevel

        # Do we have auth?
        if (self.auth_type == 'basic'):
            auth_map = parse_authorization_header(self.headers.get('Authorization',''))
            if (auth_map and auth_map['type']=='basic' and
                auth_map['username']+':'+auth_map['password']==IIIFRequestHandler.USER_PASS):
                # authz, continue
                pass
            else:
                # failed, send 401 with null image info, no service link for auth as
                # basic auth is all done via the WWW-Authenticate header
                i = IIIFInfo(api_version=self.api_version)
                i.identifier = 'null'
                i.width = 0
                i.height = 0
                return self.send_json_response(json=i.as_json(),status=401)

        if (self.iiif.info):
            # get size
            self.manipulator.srcfile=file
            self.manipulator.do_first()
            # most of info.json comes from config, a few things specific to image
            i = IIIFInfo(conf=IIIFRequestHandler.INFO,api_version=self.api_version)
            i.server_and_prefix = self.server_and_prefix
            i.identifier = self.iiif.identifier
            i.width = self.manipulator.width
            i.height = self.manipulator.height 
            i.qualities = [ "native", "color" ] #FIXME - should come from manipulator
            i.formats = [ "jpg", "png" ] #FIXME - should come from manipulator
            return self.send_json_response(i.as_json(),200)
        else:
            if (self.api_version<'2.0' and
                self.iiif.format is None and
                'Accept' in self.headers):
                # In 1.0 and 1.1 conneg was specified as an alternative to format, see:
                # http://iiif.io/api/image/1.0/#format
                # http://iiif.io/api/image/1.1/#parameters-format
                formats = { 'image/jpeg': 'jpg', 'image/tiff': 'tif',
                            'image/png': 'png', 'image/gif': 'gif',
                            'image/jp2': 'jps', 'application/pdf': 'pdf' }
                accept = do_conneg( self.headers['Accept'], formats.keys() )
                # Ignore Accept header if not recognized, should this be an error instead?
                if (accept in formats):
                    self.iiif.format = formats[accept]
            (outfile,mime_type)=self.manipulator.derive(file,iiif)
            return self.send_good_response(open(outfile,'r'),mime_type)
Beispiel #12
0
    def do_GET(self):
        """Implement the HTTP GET method

        The bulk of this code is wrapped in a big try block and anywhere
        within the code may raise an IIIFError which then results in an
        IIIF error response (section 5 of spec).
        """
        self.compliance_level=None
        # We take prefix to see whe implementation to use, / is special info
        if (self.path == '/'):
            return self.send_top_level_index_page()
        
        # Test code...
        m = re.match(r'/response_test/(\d\d\d)$', self.path)
        if (m):
            status=int(m.group(1))
            # WHAT DOES NULL info.json look like?
            # https://github.com/IIIF/auth/issues/2
            self.api_version='2.0'
            i = IIIFInfo(api_version=self.api_version)
            i.identifier = 'abc'
            i.width = 0
            i.height = 0
            i.service = { '@context': 'http://example.org/auth_context.json',
                          '@id': "http://example.com/authn_here",
                          'label': "Authenticate here" }
            return self.send_json_response(json=i.as_json(),status=status)

        # Is this a request for a prefix index page?
        m = re.match(r'/([\w\._]+)$', self.path)
        if (m and m.group(1) in IIIFRequestHandler.MANIPULATORS):
            return self.send_prefix_index_page(m.group(1))

        # Is this a request for a test page?
        m = re.match(r'/([\w\._]+)$', self.path)
        if (m):
            page_path = os.path.join(IIIFRequestHandler.PAGES_DIR,m.group(1))
            if (os.path.isfile(page_path)):
                return self.send_html_file(page_path)

        # Now assume we have an iiif request
        m = re.match(r'/([\w\._]+)/(.*)$', self.path)
        if (m):
            self.prefix = m.group(1)
            self.path = m.group(2)
            if (self.prefix in IIIFRequestHandler.MANIPULATORS):
                self.api_version = IIIFRequestHandler.MANIPULATORS[self.prefix]['api_version']
                self.iiif = IIIFRequest(baseurl='/'+self.prefix+'/',api_version=self.api_version)
                self.manipulator = IIIFRequestHandler.MANIPULATORS[self.prefix]['klass'](api_version=self.api_version)
                self.auth_type = IIIFRequestHandler.MANIPULATORS[self.prefix]['auth_type']
            else:
                # 404 - unrecognized prefix
                self.send_404_response("Not Found - prefix /%s/ is not known" % (self.prefix))
                return
        else:
            # 404 - unrecognized path structure
            self.send_404_response("Not Found - path structure not recognized")
            return
        try:
            self.do_GET_body()
        except IIIFError as e:
            e.text += " Request parameters: "+str(self.iiif)
            self.write_error_response(e)
        except Exception as ue:
            # Anything else becomes a 500 Internal Server Error
            sys.stderr.write(str(ue)+"\n")
            self.write_error_response(IIIFError(code=500,text="Something went wrong... %s.\n"%(str(ue))))
Beispiel #13
0
 def test01_str(self):
     """Test str method."""
     e = IIIFError()
     self.assertEqual(str(e), 'UNKNOWN_ERROR')
     e = IIIFError(text='aa', parameter='bb', code=404)
     self.assertEqual(str(e), 'aa, parameter=bb')