Get a historic zonefile for a name
        With `raw=1` on the query string, return the raw zone file

        Reply 200 with {'zonefile': zonefile} on success
        Reply 204 with {'error': ...} if the zone file is non-standard
        Reply 404 on not found
        Reply 502 on failure to fetch data

def GET_name_zonefile_by_hash( self, path_info, name, zonefile_hash ):
        """
        Get a historic zonefile for a name
        With `raw=1` on the query string, return the raw zone file

        Reply 200 with {'zonefile': zonefile} on success
        Reply 204 with {'error': ...} if the zone file is non-standard
        Reply 404 on not found
        Reply 502 on failure to fetch data
        """
        if not check_name(name) and not check_subdomain(name):
            return self._reply_json({'error': 'Invalid name or subdomain'}, status_code=400)
        
        if not check_string(zonefile_hash, pattern=OP_ZONEFILE_HASH_PATTERN):
            return self._reply_json({'error': 'Invalid zone file hash'}, status_code=400)

        raw = path_info['qs_values'].get('raw', '')
        raw = (raw.lower() in ['1', 'true'])

        blockstack_hostport = get_blockstackd_url()
        was_set = blockstackd_client.is_name_zonefile_hash(name, zonefile_hash, hostport=blockstack_hostport)
        if json_is_error(was_set):
            return self._reply_json({'error': was_set['error']}, status_code=was_set.get('http_status', 502))

        if not was_set['result']:
            self._reply_json({'error': 'No such zonefile'}, status_code=404)
            return

        resp = blockstackd_client.get_zonefiles(blockstack_hostport, [str(zonefile_hash)])
        if json_is_error(resp):
            self._reply_json({'error': resp['error']}, status_code=resp.get('http_status', 502))
            return

        if str(zonefile_hash) not in resp['zonefiles']:
            return self._reply_json({'error': 'Blockstack does not have this zonefile.  Try again later.'}, status_code=404)

        if raw:
            self._send_headers(status_code=200, content_type='application/octet-stream')
            self.wfile.write(resp['zonefiles'][str(zonefile_hash)])

        else:
            # make sure it's valid
            if str(zonefile_hash) not in resp['zonefiles']:
                log.debug('Failed to find zonefile hash {}, possess {}'.format(
                    str(zonefile_hash), resp['zonefiles'].keys()))
                return self._reply_json({'error': 'No such zonefile'}, status_code=404)

            zonefile_txt = resp['zonefiles'][str(zonefile_hash)]
            res = decode_name_zonefile(name, zonefile_txt)
            if res is None:
                log.error("Failed to parse zone file for {}".format(name))
                self._reply_json({'error': 'Non-standard zone file for {}'.format(name)}, status_code=204)
                return

            self._reply_json({'zonefile': zonefile_txt})

        return