Example #1
0
    def receive_packet(self, data):
        data = data[:-len(self.endseq)]

        term_info = TerminalClient.all_cookies.get(self.cookie)
        if not term_info:
            return self.shutdown()

        host_connection, term_name = term_info

        headers, content = lineterm.parse_headers(data)

        if headers["x_gterm_response"] == "capture_feedback":
            feedback = headers["x_gterm_parameters"].get("cookie")
            if feedback and feedback.isdigit() and feedback in TerminalClient.all_cookies:
                self.set_feedback_status(feedback)
            else:
                logging.warning("gtermhost: Invalid feedback cookie %s", feedback)

        elif headers["x_gterm_response"] == "create_blob":
            blob_id = headers["x_gterm_parameters"].get("blob_id")
            if not blob_id:
                logging.warning("gtermhost: No id for blob creation")
            elif "content_length" not in headers:
                logging.warning("gtermhost: No content_length specified for create_blob")
            else:
                host_connection.blob_cache.add_blob(blob_id, headers, content)

        else:
            params = {"validated": True, "headers": headers}
            host_connection.send_request_threadsafe("response", term_name, [["terminal", "graphterm_widget", [params,
                                                 base64.b64encode(content) if content else ""]]])
        self.cookie = None
        self.next_packet()
Example #2
0
    def receive_packet(self, data):
        data = data[:-len(self.endseq)]

        term_info = TerminalClient.all_cookies.get(self.cookie)
        if not term_info:
            return self.shutdown()

        host_connection, term_name = term_info

        headers, content = lineterm.parse_headers(data)

        if headers["x_gterm_response"] == "capture_feedback":
            feedback = headers["x_gterm_parameters"].get("cookie")
            if feedback and feedback.isdigit() and feedback in TerminalClient.all_cookies:
                self.set_feedback_status(feedback)
            else:
                logging.warning("gtermhost: Invalid feedback cookie %s", feedback)

        elif headers["x_gterm_response"] == "create_blob":
            blob_id = headers["x_gterm_parameters"].get("blob_id")
            if not blob_id:
                logging.warning("gtermhost: No id for blob creation")
            elif "content_length" not in headers:
                logging.warning("gtermhost: No content_length specified for create_blob")
            else:
                host_connection.blob_cache.add_blob(blob_id, headers, content)

        else:
            params = {"validated": True, "headers": headers}
            host_connection.send_request_threadsafe("response", term_name, "", [["terminal", "graphterm_widget", [params,
                                                 base64.b64encode(content) if content else ""]]])
        self.cookie = None
        self.next_packet()
Example #3
0
    def receive_packet(self, data):
        data = data[:-len(self.endseq)]

        term_info = TerminalClient.all_cookies.get(self.packet_cookie)
        if not term_info:
            return self.shutdown()
        host_connection, term_name = term_info

        headers, content = lineterm.parse_headers(data)

        resp_type = headers["x_gterm_response"]

        if resp_type == "capture_chat":
            chat_cookie = headers["x_gterm_parameters"].get("cookie")
            widget_token = headers["x_gterm_parameters"].get(
                "widget_token", "")
            if chat_cookie == self.packet_cookie:  # Redundant?
                prev_widget = self.get_chat_widget(chat_cookie)
                if prev_widget and prev_widget is not self:
                    # Only one active chat widget per terminal at a time
                    prev_widget.shutdown()
                self.chat_cookie = chat_cookie
                self._chat_widgets[chat_cookie] = self
                self.set_chat_status(True, widget_token)
            else:
                logging.warning("Invalid chat cookie %s", chat_cookie)

        elif resp_type == "create_blob":
            blob_id = headers["x_gterm_parameters"].get("blob_id")
            if not blob_id:
                logging.warning("No id for blob creation")
            elif "content_length" not in headers:
                logging.warning("No content_length specified for create_blob")
            else:
                host_connection.blob_cache.add_blob(blob_id, headers, content)

        else:
            params = {"validated": True, "headers": headers}
            args = [params, base64.b64encode(content) if content else ""]
            if not resp_type or resp_type == "pagelet":
                # HTML pagelet widget
                prev_widget = self.get_pagelet_widget(self.packet_cookie)
                if prev_widget and prev_widget is not self:
                    # Only one active pagelet widget per terminal at a time
                    prev_widget.shutdown()
                self._pagelet_widgets[self.packet_cookie] = self
                self.last_pagelet_args = args
            self.send_widget_content(*args)

        self.packet_cookie = ""
        self.next_packet()
Example #4
0
    def receive_packet(self, data):
        data = data[:-len(self.endseq)]

        term_info = TerminalClient.all_cookies.get(self.packet_cookie)
        if not term_info:
            return self.shutdown()
        host_connection, term_name = term_info

        headers, content = lineterm.parse_headers(data)

        resp_type = headers["x_gterm_response"]

        if resp_type == "capture_chat":
            chat_cookie = headers["x_gterm_parameters"].get("cookie")
            widget_token = headers["x_gterm_parameters"].get("widget_token", "")
            if chat_cookie == self.packet_cookie:  # Redundant?
                prev_widget = self.get_chat_widget(chat_cookie)
                if prev_widget and prev_widget is not self:
                    # Only one active chat widget per terminal at a time
                    prev_widget.shutdown()
                self.chat_cookie = chat_cookie
                self._chat_widgets[chat_cookie] = self
                self.set_chat_status(True, widget_token)
            else:
                logging.warning("Invalid chat cookie %s", chat_cookie)

        elif resp_type == "create_blob":
            blob_id = headers["x_gterm_parameters"].get("blob_id")
            if not blob_id:
                logging.warning("No id for blob creation")
            elif "content_length" not in headers:
                logging.warning("No content_length specified for create_blob")
            else:
                host_connection.blob_cache.add_blob(blob_id, headers, content)

        else:
            params = {"validated": True, "headers": headers}
            args = [params, base64.b64encode(content) if content else ""]
            if not resp_type or resp_type == "pagelet":
                # HTML pagelet widget
                prev_widget = self.get_pagelet_widget(self.packet_cookie)
                if prev_widget and prev_widget is not self:
                    # Only one active pagelet widget per terminal at a time
                    prev_widget.shutdown()
                self._pagelet_widgets[self.packet_cookie] = self
                self.last_pagelet_args = args
            self.send_widget_content(*args)

        self.packet_cookie = ""
        self.next_packet()
Example #5
0
    def remote_request(self, term_name, req_list):
        """
        Setup commands:
          reconnect

        Input commands:
          incomplete_input <line>
          input <line>
          click_paste <text> <file_url> {command:, clear_last:, normalize:, enter:}
          paste_command <text>
          get_finder <kind> <directory>
          save_file <filepath> <filedata>

        Output commands:
          completed_input <line>
          prompt <str>
          stdin <str>
          stdout <str>
          stderr <str>
        """
        try:
            lterm_cookie = self.terms.get(term_name)
            resp_list = []
            for cmd in req_list:
                action = cmd.pop(0)

                if action == "shutdown":
                    if cmd:
                        logging.warning("gtermhost: SHUTDOWN %s", cmd[0])
                    self.shutdown()

                elif action == "reconnect":
                    if self.lineterm:
                        self.lineterm.reconnect(term_name, cmd[0])

                elif action == "set_size":
                    if term_name != OSHELL_NAME:
                        self.xterm(term_name, cmd[0][0], cmd[0][1])

                elif action == "kill_term":
                    self.remove_term(term_name)

                elif action == "clear_term":
                    if self.lineterm:
                        self.lineterm.clear(term_name)

                elif action == "export_environment":
                    if self.lineterm:
                        self.lineterm.export_environment(term_name)

                elif action == "keypress":
                    if self.lineterm:
                        self.lineterm.term_write(term_name, cmd[0].encode(self.term_encoding, "ignore"))

                elif action == "feedback":
                    widget_stream = WidgetStream.get_feedback_connection(lterm_cookie)
                    if widget_stream:
                        widget_stream.send_packet(cmd[0].encode(self.term_encoding, "ignore"))

                elif action == "save_file":
                    if self.lineterm:
                        self.lineterm.save_file(term_name, cmd[0], cmd[1])

                elif action == "click_paste":
                    # click_paste: text, file_url, {command:, clear_last:, normalize:, enter:}
                    if self.lineterm:
                        paste_text = self.lineterm.click_paste(term_name, cmd[0], cmd[1], cmd[2])
                        self.paste_command(term_name, paste_text)

                elif action == "paste_command":
                    # paste_command: command_line
                    self.paste_command(term_name, cmd[0])

                elif action == "clear_last_entry":
                    if self.lineterm:
                        self.lineterm.clear_last_entry(term_name, long(cmd[0]))

                elif action == "get_finder":
                    if self.lineterm:
                        self.lineterm.get_finder(term_name, cmd[0], cmd[1])

                elif action == "incomplete_input":
                    cmd_incomplete = cmd[0].encode("ascii", "ignore")
                    dummy, sep, text = cmd_incomplete.rpartition(" ")
                    options = otrace.OShell.instance.completer(text, 0, line=cmd_incomplete, all=True)
                    if text:
                        options = [cmd_incomplete[:-len(text)]+option for option in options]
                    else:
                        options = [cmd_incomplete+option for option in options]
                    resp_list.append(["completed_input", options])   # Not escaped; handle as text

                elif action == "input":
                    cmd_input = cmd[0].encode("ascii", "ignore").lstrip()   # Unescaped text
                    here_doc = base64.b64decode(cmd[1]) if cmd[1] else cmd[1]
                    entry_list = []

                    if cmd_input == "cat episode4.txt":
                        # Easter egg
                        std_out, std_err = Episode4, ""
                    else:
                        std_out, std_err = otrace.OShell.instance.execute(cmd_input, here_doc=here_doc)
                    resp_list.append(["input", cmd[0]])   # Not escaped; handle as text

                    prompt, cur_dir_path = otrace.OShell.instance.get_prompt()
                    resp_list.append(["prompt", cgi.escape(prompt), "file://"+urllib.quote(cur_dir_path)])

                    auth_html = False
                    if lterm_cookie and std_out.startswith(HTML_ESCAPES[0]):
                        auth_prefix = HTML_ESCAPES[0]+lterm_cookie+HTML_ESCAPES[1]
                        auth_html = std_out.startswith(auth_prefix)
                        if auth_html:
                            offset = len(auth_prefix)
                        else:
                            # Unauthenticated html
                            offset = std_out.find(HTML_ESCAPES[1])+len(HTML_ESCAPES[1])

                        if std_out.endswith(HTML_ESCAPES[-1]):
                            html_output = std_out[offset:-len(HTML_ESCAPES[-1])]
                        elif std_out.endswith(HTML_ESCAPES[-1]+"\n"):
                            html_output = std_out[offset:-len(HTML_ESCAPES[-1])-1]
                        else:
                            html_output = std_out[offset:]

                        headers, content = lineterm.parse_headers(html_output)

                        if auth_html:
                            resp_list.append(["html_output", content])
                        else:
                            # Unauthenticated; extract plain text from html
                            try:
                                import lxml.html
                                std_out = lxml.html.fromstring(content).text_content()
                            except Exception:
                                std_out = content

                    if not auth_html:
                        entry_list.append('<pre class="output">')
                        if std_out and std_out != "_NoPrompt_":
                            entry_list.append('<span class="stdout">%s</span>' % cgi.escape(std_out))
                        if std_err:
                            entry_list.append('<span class="stderr">%s</span>' % cgi.escape(std_err))
                        entry_list.append('</pre>')
                        resp_list.append(["output", "\n".join(entry_list)])

                elif action == "file_request":
                    request_id, request_method, file_path, if_mod_since = cmd
                    status = (404, "Not Found")
                    etag = None
                    last_modified = None
                    content_type = None
                    content_length = None
                    content_b64 = ""
                    remote_modtime = None
                    if if_mod_since:
                        remote_modtime = str2datetime(if_mod_since)

                    if not file_path.startswith("/"):
                        # Blob request
                        btime, bheaders, bcontent = self.blob_cache.get_blob(file_path)
                        if bheaders:
                            mod_datetime = datetime.datetime.fromtimestamp(btime)
                            if remote_modtime and remote_modtime >= mod_datetime:
                                # Somewhat redundant check, since blobs are never modified!
                                status = (304, "Not Modified")
                            else:
                                last_modified = datetime2str(mod_datetime)
                                etag = file_path
                                content_type = bheaders.get("content_type") or "text/html"
                                content_length = bheaders["content_length"]
                                if request_method != "HEAD":
                                    content_b64 = bcontent # B64 encoded
                                status = (200, "OK")
                    else:
                        abspath = file_path
                        if os.path.sep != "/":
                            abspath = abspath.replace("/", os.path.sep)

                        if os.path.isfile(abspath) and os.access(abspath, os.R_OK):
                            mod_datetime = datetime.datetime.fromtimestamp(os.path.getmtime(abspath))

                            if remote_modtime and remote_modtime >= mod_datetime:
                                status = (304, "Not Modified")
                            else:
                                # Read file contents
                                try:
                                    last_modified = datetime2str(mod_datetime)

                                    mime_type, encoding = mimetypes.guess_type(abspath)
                                    if mime_type:
                                        content_type = mime_type

                                    with open(abspath, "rb") as file:
                                        data = file.read()
                                        hasher = hashlib.sha1()
                                        hasher.update(data)
                                        digest = hasher.hexdigest()
                                        etag = '"%s"' % digest
                                        if request_method == "HEAD":
                                            content_length = len(data)
                                        else:
                                            content_b64 = base64.b64encode(data)
                                        status = (200, "OK")
                                except Exception:
                                    pass

                    resp_list.append(["file_response", request_id,
                                      dict(status=status, last_modified=last_modified,
                                           etag=etag,
                                           content_type=content_type, content_length=content_length,
                                           content_b64=content_b64)])

                elif action == "errmsg":
                    logging.warning("remote_request: ERROR %s", cmd[0])
                else:
                    raise Exception("Invalid action: "+action)
            self.remote_response(term_name, "", resp_list);
        except Exception, excp:
            import traceback
            errmsg = "%s\n%s" % (excp, traceback.format_exc())
            print >> sys.stderr, "TerminalClient.remote_request: "+errmsg
            self.remote_response(term_name, "", [["errmsg", errmsg]])
Example #6
0
                            offset = len(auth_prefix)
                        else:
                            # Unauthenticated html
                            offset = std_out.find(HTML_ESCAPES[1]) + len(
                                HTML_ESCAPES[1])

                        if std_out.endswith(HTML_ESCAPES[-1]):
                            html_output = std_out[offset:-len(HTML_ESCAPES[-1]
                                                              )]
                        elif std_out.endswith(HTML_ESCAPES[-1] + "\n"):
                            html_output = std_out[
                                offset:-len(HTML_ESCAPES[-1]) - 1]
                        else:
                            html_output = std_out[offset:]

                        headers, content = lineterm.parse_headers(html_output)

                        if auth_html:
                            resp_list.append(["html_output", content])
                        else:
                            # Unauthenticated; extract plain text from html
                            try:
                                import lxml.html
                                std_out = lxml.html.fromstring(
                                    content).text_content()
                            except Exception:
                                std_out = content

                    if not auth_html:
                        entry_list.append('<pre class="output">')
                        if std_out and std_out != "_NoPrompt_":
Example #7
0
                        auth_prefix = HTML_ESCAPES[0]+lterm_cookie+HTML_ESCAPES[1]
                        auth_html = std_out.startswith(auth_prefix)
                        if auth_html:
                            offset = len(auth_prefix)
                        else:
                            # Unauthenticated html
                            offset = std_out.find(HTML_ESCAPES[1])+len(HTML_ESCAPES[1])

                        if std_out.endswith(HTML_ESCAPES[-1]):
                            html_output = std_out[offset:-len(HTML_ESCAPES[-1])]
                        elif std_out.endswith(HTML_ESCAPES[-1]+"\n"):
                            html_output = std_out[offset:-len(HTML_ESCAPES[-1])-1]
                        else:
                            html_output = std_out[offset:]

                        headers, content = lineterm.parse_headers(html_output)

                        if auth_html:
                            resp_list.append(["html_output", content])
                        else:
                            # Unauthenticated; extract plain text from html
                            try:
                                import lxml.html
                                std_out = lxml.html.fromstring(content).text_content()
                            except Exception:
                                std_out = content

                    if not auth_html:
                        entry_list.append('<pre class="output">')
                        if std_out and std_out != "_NoPrompt_":
                            entry_list.append('<span class="stdout">%s</span>' % cgi.escape(std_out))
Example #8
0
    def remote_request(self, term_name, from_user, req_list):
        """
        Setup commands:
          reconnect

        Input commands:
          incomplete_input <line>
          input <line>
          click_paste <text> <file_url> {command:, clear_last:, normalize:, enter:}
          paste_command <text>
          get_finder <kind> <directory>
          save_data <save_params> <filedata>
          open_notebook <filepath> <prompts> <content>
          close_notebook <discard>
          save_notebook <filepath> <input_data> <params>
          add_cell <new_cell_type> <init_text> <before_cell_index>
          select_cell <cell_index> <move_up> <next_code>
          select_page <move_up> <endpoint> <slide>
          move_cell <move_up>
          delete_cell <move_up>
          merge_above
          erase_output <all_cells>
          update_type <cell_type>
          complete_cell <incomplete_line>
          update_cell <cellIndex> <execute> <save> <input_data>

        Output commands:
          completed_input <line>
          prompt <str>
          stdin <str>
          stdout <str>
          stderr <str>
        """
        try:
            lterm_cookie, blobs = self.terms.get(term_name, [None, None])
            resp_list = []
            for cmd in req_list:
                action = cmd.pop(0)

                if action == "shutdown":
                    if cmd:
                        logging.warning("gtermhost: SHUTDOWN %s", cmd[0])
                    self.shutdown()

                elif action == "reconnect":
                    if self.lineterm:
                        self.lineterm.reconnect(term_name, cmd[0])

                elif action == "set_size":
                    if term_name != OSHELL_NAME:
                        self.xterm(term_name, cmd[0][0], cmd[0][1], cmd[0][2], cmd[0][3], cmd[0][4])

                elif action == "kill_term":
                    self.remove_term(term_name)

                elif action == "clear_term":
                    if self.lineterm:
                        self.lineterm.clear(term_name)

                elif action == "export_environment":
                    if self.lineterm:
                        self.lineterm.export_environment(term_name, cmd[0])

                elif action == "keypress":
                    if self.lineterm:
                        self.lineterm.term_write(term_name, cmd[0].encode(self.term_encoding, "ignore"))

                elif action == "feedback":
                    msg = from_user + ": " + cmd[0] if from_user else cmd[0]
                    widget_stream = WidgetStream.get_feedback_connection(lterm_cookie)
                    if widget_stream:
                        widget_stream.send_packet(msg.encode(self.term_encoding, "ignore"))

                elif action == "save_data":
                    # save_data <save_params> <filedata>
                    if self.lineterm:
                        self.lineterm.save_data(term_name, cmd[0], cmd[1])

                elif action == "click_paste":
                    # click_paste: text, file_url, {command:, clear_last:, normalize:, enter:}
                    if self.lineterm:
                        paste_text = self.lineterm.click_paste(term_name, cmd[0], cmd[1], cmd[2])
                        self.paste_command(term_name, paste_text)

                elif action == "open_notebook":
                    # open_notebook <filepath> <prompts> <content>
                    if self.lineterm:
                        self.lineterm.open_notebook(term_name, cmd[0], cmd[1], cmd[2])

                elif action == "close_notebook":
                    # close_notebook <discard>
                    if self.lineterm:
                        self.lineterm.close_notebook(term_name, cmd[0])

                elif action == "save_notebook":
                    # save_notebook <filepath> <input_data> <params>
                    if self.lineterm:
                        self.lineterm.save_notebook(term_name, cmd[0], cmd[1], cmd[2])

                elif action == "add_cell":
                    # add_cell <new_cell_type> <init_text> <before_cell_index>
                    if self.lineterm:
                        self.lineterm.add_cell(term_name, cmd[0], cmd[1], cmd[2])

                elif action == "select_cell":
                    # select_cell <cell_index> <move_up> <next_code>
                    if self.lineterm:
                        self.lineterm.select_cell(term_name, cmd[0], cmd[1], cmd[2])

                elif action == "select_page":
                    # select_page <move_up> <endpoint> <slide>
                    if self.lineterm:
                        self.lineterm.select_page(term_name, cmd[0], cmd[1], cmd[2])

                elif action == "move_cell":
                    # move_cell <move_up>
                    if self.lineterm:
                        self.lineterm.move_cell(term_name, cmd[0])

                elif action == "delete_cell":
                    # delete_cell <move_up>
                    if self.lineterm:
                        self.lineterm.delete_cell(term_name, cmd[0])

                elif action == "merge_above":
                    # merge_above
                    if self.lineterm:
                        self.lineterm.merge_above(term_name)

                elif action == "erase_output":
                    # erase_output <all_cells>
                    if self.lineterm:
                        self.lineterm.erase_output(term_name, cmd[0])

                elif action == "update_type":
                    # update_type <cell_type>
                    if self.lineterm:
                        self.lineterm.update_type(term_name, cmd[0])

                elif action == "complete_cell":
                    # complete_cell <incomplete_line>
                    if self.lineterm:
                        self.lineterm.complete_cell(term_name, cmd[0])

                elif action == "update_cell":
                    # update_cell <cellIndex> <execute> <save>, <input_data>
                    if self.lineterm:
                        self.lineterm.update_cell(term_name, cmd[0], cmd[1], cmd[2], cmd[3])

                elif action == "paste_command":
                    # paste_command: command_line
                    self.paste_command(term_name, cmd[0])

                elif action == "clear_last_entry":
                    if self.lineterm:
                        self.lineterm.clear_last_entry(term_name, long(cmd[0]))

                elif action == "get_finder":
                    if self.lineterm:
                        self.lineterm.get_finder(term_name, cmd[0], cmd[1])

                elif action == "incomplete_input":
                    cmd_incomplete = cmd[0].encode("ascii", "ignore")
                    dummy, sep, text = cmd_incomplete.rpartition(" ")
                    options = otrace.OShell.instance.completer(text, 0, line=cmd_incomplete, all=True)
                    if text:
                        options = [cmd_incomplete[:-len(text)]+option for option in options]
                    else:
                        options = [cmd_incomplete+option for option in options]
                    resp_list.append(["completed_input", options])   # Not escaped; handle as text

                elif action == "input":
                    cmd_input = cmd[0].encode("ascii", "ignore").lstrip()   # Unescaped text
                    here_doc = base64.b64decode(cmd[1]) if cmd[1] else cmd[1]
                    entry_list = []

                    if cmd_input == "cat episode4.txt":
                        # Easter egg
                        std_out, std_err = Episode4, ""
                    else:
                        std_out, std_err = otrace.OShell.instance.execute(cmd_input, here_doc=here_doc)
                    resp_list.append(["input", cmd[0]])   # Not escaped; handle as text

                    prompt, cur_dir_path = otrace.OShell.instance.get_prompt()
                    resp_list.append(["prompt", cgi.escape(prompt), "file://"+urllib.quote(cur_dir_path)])

                    auth_html = False
                    if lterm_cookie and std_out.startswith(HTML_ESCAPES[0]):
                        auth_prefix = HTML_ESCAPES[0]+lterm_cookie+HTML_ESCAPES[1]
                        auth_html = std_out.startswith(auth_prefix)
                        if auth_html:
                            offset = len(auth_prefix)
                        else:
                            # Unauthenticated html
                            offset = std_out.find(HTML_ESCAPES[1])+len(HTML_ESCAPES[1])

                        if std_out.endswith(HTML_ESCAPES[-1]):
                            html_output = std_out[offset:-len(HTML_ESCAPES[-1])]
                        elif std_out.endswith(HTML_ESCAPES[-1]+"\n"):
                            html_output = std_out[offset:-len(HTML_ESCAPES[-1])-1]
                        else:
                            html_output = std_out[offset:]

                        headers, content = lineterm.parse_headers(html_output)

                        if auth_html:
                            resp_list.append(["html_output", content])
                        else:
                            # Unauthenticated; extract plain text from html
                            try:
                                import lxml.html
                                std_out = lxml.html.fromstring(content).text_content()
                            except Exception:
                                std_out = content

                    if not auth_html:
                        entry_list.append('<pre class="output">')
                        if std_out and std_out != "_NoPrompt_":
                            entry_list.append('<span class="stdout">%s</span>' % cgi.escape(std_out))
                        if std_err:
                            entry_list.append('<span class="stderr">%s</span>' % cgi.escape(std_err))
                        entry_list.append('</pre>')
                        resp_list.append(["output", "\n".join(entry_list)])

                elif action == "file_request":
                    request_id, request_method, file_path, if_mod_since = cmd
                    status = (404, "Not Found")
                    etag = None
                    last_modified = None
                    content_type = None
                    content_length = None
                    content_b64 = ""
                    remote_modtime = None
                    if if_mod_since:
                        remote_modtime = str2datetime(if_mod_since)

                    if not file_path.startswith("/"):
                        # Blob request
                        btime, bheaders, bcontent = self.blob_cache.get_blob(file_path)
                        if bheaders:
                            mod_datetime = datetime.datetime.fromtimestamp(btime)
                            if remote_modtime and remote_modtime >= mod_datetime:
                                # Somewhat redundant check, since blobs are never modified!
                                status = (304, "Not Modified")
                            else:
                                last_modified = datetime2str(mod_datetime)
                                etag = file_path
                                content_type = bheaders.get("content_type") or "text/html"
                                content_length = bheaders["content_length"]
                                if request_method != "HEAD":
                                    content_b64 = bcontent # B64 encoded
                                status = (200, "OK")
                    else:
                        abspath = file_path
                        if os.path.sep != "/":
                            abspath = abspath.replace("/", os.path.sep)

                        if os.path.isfile(abspath) and os.access(abspath, os.R_OK):
                            mod_datetime = datetime.datetime.fromtimestamp(os.path.getmtime(abspath))

                            if remote_modtime and remote_modtime >= mod_datetime:
                                status = (304, "Not Modified")
                            else:
                                # Read file contents
                                try:
                                    last_modified = datetime2str(mod_datetime)

                                    mime_type, encoding = mimetypes.guess_type(abspath)
                                    if mime_type:
                                        content_type = mime_type

                                    with open(abspath, "rb") as file:
                                        data = file.read()
                                        hasher = hashlib.sha1()
                                        hasher.update(data)
                                        digest = hasher.hexdigest()
                                        etag = '"%s"' % digest
                                        if request_method == "HEAD":
                                            content_length = len(data)
                                        else:
                                            content_b64 = base64.b64encode(data)
                                        status = (200, "OK")
                                except Exception:
                                    pass

                    resp_list.append(["file_response", request_id,
                                      dict(status=status, last_modified=last_modified,
                                           etag=etag,
                                           content_type=content_type, content_length=content_length,
                                           content_b64=content_b64)])

                elif action == "errmsg":
                    logging.warning("remote_request: ERROR %s", cmd[0])
                else:
                    raise Exception("Invalid action: "+action)
            self.remote_response(term_name, "", resp_list);
        except Exception, excp:
            import traceback
            errmsg = "%s\n%s" % (excp, traceback.format_exc())
            print >> sys.stderr, "TerminalClient.remote_request: "+errmsg
            self.remote_response(term_name, "", [["errmsg", errmsg]])