# $SnapHashLicense:
#
# SnapLogic - Open source data services
#
# Copyright (C) 2008, SnapLogic, Inc. All rights reserved.
#
# See http://www.snaplogic.org for more information about
# the SnapLogic project.
#
# This program is free software, distributed under the terms of
# the GNU General Public License Version 2. See the LEGAL file
# at the top of the source tree.
#
# "SnapLogic" is a trademark of SnapLogic, Inc.
#
#
# $
# $Id: url_reader.py 2428 2008-04-11 21:04:43Z kurt $
"""
Contains the SnapStream URLReader class.
"""
from socket import gaierror
import httplib
from snaplogic.common import snap_http_lib
from snaplogic.common.snap_exceptions import *
from snaplogic.common.snapstream.reader import Reader
from snaplogic.common.snapstream.selectable_binary_pipe import SelectableBinaryPipe
from snaplogic.common.snapstream.selectable_rp_pipe import SelectableRPReaderPipe
from snaplogic import rp
class URLReader(Reader):
def __init__(self, url, content_types=None, view_name='Unspecified'):
super(URLReader, self).__init__(url, view_name)
self._connect(content_types)
def _make_accept_header(self, accept_types):
if accept_types is None:
accept_types = rp.get_supported_content_types()
return ', '.join(accept_types)
def _connect(self, accept_types):
accept_header = self._make_accept_header(accept_types)
headers = {"Accept": accept_header}
try:
self._conn = snap_http_lib.urlopen("GET", self.request_url, None, headers)
except gaierror, e:
raise self._exception(SnapStreamConnectionError, e.args[2])
try:
status = self._conn.getStatus()
if status != httplib.OK:
if status == httplib.UNSUPPORTED_MEDIA_TYPE:
raise self._exception(SnapStreamNegotiationError,
"No compatible content type handler found on remote server.",
('URL', self.request_url))
else:
raise self._exception(SnapStreamNegotiationError, 'Unexpected HTTP status code in URLReader.',
('status', status))
headers = self._conn.getHeaders()
if 'content-type' not in headers:
raise self._exception(SnapStreamNegotiationError, "Missing Content-Type header.")
content_type = headers['content-type']
self._negotiate(accept_types, content_type)
finally:
# If no content type was negotiated, then it failed and we must close the connection
if self.content_type is None:
self._conn.close()
def _negotiate(self, accept_types, content_type):
if accept_types is None:
# Record stream mode
self.stream_mode = self.RECORD_STREAM
selected_rp = rp.get_rp(content_type)
if selected_rp is not None:
self.content_type = content_type
self._pipe = SelectableRPReaderPipe(selected_rp)
else:
# Binary stream mode
self.stream_mode = self.BINARY_STREAM
self.content_type = rp.select_content_type([content_type], accept_types)
if self.content_type is not None:
self._pipe = SelectableBinaryPipe()
# At this point, negotiation must have failed for the content type specified by the remote server if
# no content type is set still.
if self.content_type is None:
raise self._exception(SnapStreamNegotiationError, "No compatible content type handler found locally.",
('Remote content type', content_type))
|