HEX
Server: Apache/2.2.34 (Unix) mod_fastcgi/mod_fastcgi-SNAP-0910052141
System: Linux Kou-Etsu-Dou 4.4.59+ #25556 SMP PREEMPT Thu Mar 4 18:03:46 CST 2021 x86_64
User: hosam (1026)
PHP: 7.2.29
Disabled: NONE
Upload Files
File: /volume1/@appstore/HyperBackup/addon/openstack_swift/python/swift_agent.py
#!/usr/bin/env python
#-*-coding: utf-8 -*-

import os, sys, json
from struct import pack, unpack
from time import strptime, mktime
from syslog import syslog, LOG_ERR

debug = False
def log_debug(*args):
	if debug:
		print >> sys.stderr, ' '.join(args)

def _is_scoket_exception(e):
	import socket
	if type(e) == socket.gaierror or type(e) == socket.error or type(e) == socket.herror or type(e) == socket.timeout:
		return True
	return False

def _convert_socket_error_code(message):
	error_code = -1
	if -1 != message.find("[Errno -2] Name or service not known"):
		error_code = -2
	elif -1 != message.find("[Errno -3] Temporary failure in name resolution"):
		error_code = -2
	elif -1 != message.find("[Errno -5] No address associated with hostname"):
		error_code = -2
	elif -1 != message.find("[Errno 110] Connection timed out"):
		error_code = 408
	elif -1 != message.find("[Errno 101] Network is unreachable"):
		error_code = -4
	elif -1 != message.find("[Errno 111] Connection refused"):
		error_code = -4
	elif -1 != message.find("[Errno 113] No route to host"):
		error_code = -4
	elif -1 != message.find("[Errno 104] Connection reset by peer"):
		error_code = -4
	elif -1 != message.find("[Errno 32] Broken pipe"):
		error_code = 408
	return error_code

def _is_ssl_timeout(message):
	#ssl.SSLErr_timeouteption log
	if -1 != message.find("timed out"):
		# The read operation timed out
		# The write operation timed out
		# The handshake operation timed out
		return True
	return False

def _convert_socket_exception(e):
	import socket

	error_code = -1
	error_msg = 'Unknown'
	error_cls = 'Unknown'

	try:
		error_cls = type(e).__name__
		if hasattr(e, '__module__') and e.__module__:
			error_cls = e.__module__ + '.' + error_cls

		if type(e) == socket.gaierror:
			if hasattr(e, 'strerror') and e.strerror:
				error_msg = e.strerror
			if e.errno == -2:
				# socket.gaierror: [Errno -2] Name or service not known
				# 1. dns not set
				# 2. set to a wrong dns
				error_code = -2
			elif e.errno == -3:
				# socket.gaierror: [Errno -3] Temporary failure in name resolution
				# man gai_strerror, and find EAI_AGAIN:
				# The name server returned a temporary failure indication.  Try again later.
				error_code = -2
			elif e.errno == -5:
				# socket.gaierror: [Errno -5] No address associated with hostname
				# man gai_strerror, and find EAI_NODATA:
				# The specified network host exists, but does not have any network addresses defined.
				error_code = -2
			elif e.errno < 100 and e.errno > 0:
				error_code = e.errno
		elif type(e) == socket.error or type(e) == socket.herror:
			if hasattr(e, 'strerror') and e.strerror:
				error_msg = e.strerror
			elif hasattr(e, 'args'):
				error_msg = str(e.args)
				if -1 != error_msg.find('Tunnel connection failed'):
					error_code = -4

			if e.errno == socket.errno.ETIMEDOUT:
				# socket.error: [Errno 110] Connection timed out
				error_code = 408
			elif e.errno == socket.errno.ENETUNREACH:
				# socket.error: [Errno 101] Network is unreachable
				error_code = -4
			elif e.errno == socket.errno.ECONNREFUSED:
				# socket.error: [Errno 111] Connection refused
				error_code = -4
			elif e.errno == socket.errno.EHOSTUNREACH:
				# socket.error: [Errno 113] No route to host
				error_code = -4
			elif e.errno == socket.errno.ECONNRESET:
				# socket.error: [Errno 104] Connection reset by peer
				error_code = -4
			elif e.errno == socket.errno.EPIPE:
				# socket.error: [Errno 32] Broken pipe
				error_code = 408
			elif e.errno < 100 and e.errno > 0:
				error_code = e.errno
			#syslog(LOG_ERR, "get network error %d:%s" % (e.errno, error_msg))
		elif type(e) == socket.timeout:
			error_msg = 'timed out'
			error_code = 408
		else:
			syslog(LOG_ERR, "BUG: exception [%s], type [%s]" % (str(e), type(e)))
		#syslog(LOG_ERR, "error %s:%d:%s" % (error_cls, error_code, str(error_msg)))

		if -1 == error_code:
			if hasattr(e, "args"):
				syslog(LOG_ERR, "error args: [%s]" % (str(e.args)))
			if hasattr(e, "errno"):
				syslog(LOG_ERR, "error errno: [%s]" % (str(e.errno)))
			if hasattr(e, "strerror"):
				syslog(LOG_ERR, "error strerror: [%s]" % (str(e.strerror)))
	except Exception as ee:
		syslog(LOG_ERR, "parse socket exception failed: [%s]" % (str(ee)))
		pass

	return {
		'success': False,
		'error_class': error_cls,
		'error_message': error_msg,
		'error_code': error_code
	}
def _convert_exception(e):
	import swiftclient
	import keystoneclient
	import requests
	import socket
	import httplib
	import ssl

	error_code = -1
	error_msg = 'Unknown'
	error_cls = 'Unknown'

	try:
		error_cls = type(e).__name__
		if hasattr(e, '__module__') and e.__module__:
			error_cls = e.__module__ + '.' + error_cls

		try:
			if type(e.message) is unicode:
				error_msg = repr(e.message).split('\\n')[0]
			else:
				error_msg = str(e.message).split('\n')[0]
			log_debug("\033[31mexception: \033[0m", error_msg)
		except:
			log_debug("\033[31mexception: \033[0m", "could not parse error msg")
		if type(e) == swiftclient.ClientException:
			if hasattr(e, "http_status"):
				if e.http_status == 400 and e.message == "Refresh access token failed":
					error_code = 401
				elif e.http_status >= 100 and e.http_status < 700:
					error_code = e.http_status
		elif type(e) == keystoneclient.exceptions.SSLError:
			error_code = -4
		elif type(e) == keystoneclient.exceptions.RequestTimeout:
			error_code = 408
		elif type(e) == keystoneclient.exceptions.ConnectionRefused:
			error_code = _convert_socket_error_code(str(e))
		elif type(e) == keystoneclient.exceptions.BadRequest:
			if hasattr(e, "http_status"):
				error_code = e.http_status
			if hasattr(e, "message"):
				error_msg = e.message
			if error_code == 400 and (error_msg == "Username should not contain white spaces" \
					or error_msg == 'Expecting username' or error_msg == 'Expecting apiKey'):
				error_code = 401
		elif type(e) == TypeError:
			# this exception will raise when base64 decode for auth failed
			if error_msg == "Incorrect padding":
				error_code = 401
		elif type(e) == UnicodeDecodeError:
			error_code = -5
		elif type(e) == requests.exceptions.ConnectionError:
			error_code = -4
			if type(e.args[0]) == requests.packages.urllib3.exceptions.ProtocolError:
				if "BadStatusLine" in str(e.args[0]):
					error_code = -4
				elif _is_scoket_exception(e.args[0].args[1]):
					return _convert_socket_exception(e.args[0].args[1])
				else:
					syslog(LOG_ERR, "ProtocolError: exception [%s], type [%s]" % (str(e.args[0].args[1]), type(e.args[0].args[1])))
			elif type(e.args[0]) == requests.packages.urllib3.exceptions.MaxRetryError:
				if hasattr(e.args[0], 'reason') and e.args[0].reason:
					if type(e.args[0].reason) == requests.packages.urllib3.exceptions.NewConnectionError:
						error_code = _convert_socket_error_code(str(e.args[0].reason))
					else:
						syslog(LOG_ERR, "MaxRetryError: exception [%s], type [%s]" % (str(e.args[0].reason), type(e.args[0].reason)))
			elif _is_scoket_exception(e.args[0]):
				return _convert_socket_exception(e.args[0])
			elif type(e.args[0]) == ssl.SSLError or type(e.args[0]) == requests.packages.urllib3.exceptions.SSLError:
				if hasattr(e.args[0], 'message') and e.args[0].message:
					error_msg = e.args[0].message
				if _is_ssl_timeout(str(error_msg)):
					error_code = 408
				else:
					syslog(LOG_ERR, "SSLError: exception [%s], type [%s]" % (str(error_msg), type(error_msg)))
		elif type(e) == requests.exceptions.SSLError:
			error_code = -4
			# EOF occurred in violation of protocol
			# SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC
			# SSL: SSLV3_ALERT_BAD_RECORD_MAC
			# SSL: SSLV3_ALERT_ILLEGAL_PARAMETER
			# SSL: TLSV1_ALERT_DECRYPT_ERROR
			# SSL: TLSV1_ALERT_DECODE_ERROR
			# SSL: CERTIFICATE_VERIFY_FAILED
			if _is_ssl_timeout(str(e)):
				error_code = 408
		elif type(e) == requests.packages.urllib3.exceptions.NewConnectionError:
			error_code = _convert_socket_error_code(str(e))
		elif type(e) == requests.packages.urllib3.exceptions.ConnectTimeoutError:
			error_code = 408
		elif type(e) == requests.packages.urllib3.exceptions.ReadTimeoutError:
			error_code = 408
		elif type(e) == requests.exceptions.ConnectTimeout:
			error_code = 408
		elif type(e) == requests.exceptions.ReadTimeout:
			error_code = 408
		elif type(e) == httplib.ResponseNotReady:
			error_code = -4
		elif type(e) == httplib.BadStatusLine:
			error_code = -4
		elif type(e) == httplib.IncompleteRead:
			error_code = -4
		elif type(e) == ssl.SSLError:
			error_code = -4
			if hasattr(e, "strerror") and e.strerror:
				# SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC
				# SSL: SSLV3_ALERT_BAD_RECORD_MAC
				# SSL: CERTIFICATE_VERIFY_FAILED
				error_msg = e.strerror
			if _is_ssl_timeout(str(error_msg)):
				error_code = 408
		elif type(e) == ssl.SSLEOFError:
			# ssl.SSLEOFError: [Errno 8] EOF occurred in violation of protocol
			if hasattr(e, 'strerror') and e.strerror:
				error_msg = e.strerror
			error_code = -4
		elif type(e) == IOError:
			if hasattr(e, 'strerror') and e.strerror:
				error_msg = e.strerror
			error_code = _convert_socket_error_code(str(e))
		elif _is_scoket_exception(e):
			return _convert_socket_exception(e)
		else:
			syslog(LOG_ERR, "exception [%s]" % str(e))
			syslog(LOG_ERR, "type [%s]" % type(e))
		#syslog(LOG_ERR, "error %s:%d:%s" % (error_cls, error_code, str(error_msg)))

		if -1 == error_code:
			if hasattr(e, "args"):
				syslog(LOG_ERR, "error args: [%s]" % (str(e.args)))
			if hasattr(e, "errno"):
				syslog(LOG_ERR, "error errno: [%s]" % (str(e.errno)))
			if hasattr(e, "strerror"):
				syslog(LOG_ERR, "error strerror: [%s]" % (str(e.strerror)))
	except Exception as ee:
		syslog(LOG_ERR, "parse exception failed: [%s]" % (str(ee)))
		pass

	return {
		'success': False,
		'error_class': error_cls,
		'error_message': error_msg,
		'error_code': error_code
	}
def _convert_GMT_time_str(val):
	origin_tz = None
	if os.environ.get('TZ'):
		origin_tz = os.environ.get('TZ')
	os.environ['TZ'] = 'GMT'

	timestamp = int(mktime(strptime(val, '%a, %d %b %Y %H:%M:%S %Z')))

	if origin_tz:
		os.environ['TZ'] = origin_tz
	return timestamp
def _convert_UTC_time_str(val):
	origin_tz = None
	if os.environ.get('TZ'):
		origin_tz = os.environ.get('TZ')
	os.environ['TZ'] = 'UTC'

	time_val, sec_xtime = str(val).split('.')
	timestamp = int(mktime(strptime(time_val, '%Y-%m-%dT%H:%M:%S')))

	sec_xtime = sec_xtime.rstrip('Z')
	if int(sec_xtime) > 0:
		timestamp += 1

	if origin_tz:
		os.environ['TZ'] = origin_tz
	return timestamp
def _convert_properties(properties):
	out_json = {
		# 2015-10-01T02:52:24.169600 / 1443667944.169600 -> 1443667945
		'LastModified': _convert_UTC_time_str(properties.get('last_modified')),
		'ETag': properties.get('hash'),
		'ContentType': properties.get('content_type'),
		'ContentLength': properties.get('bytes')
	}
	return out_json
def _convert_properties_by_dict(properties):
	out_json = {
		'LastModified': _convert_GMT_time_str(properties.get('last-modified')),
		'ETag': properties.get('etag'),
		'ContentType': properties.get('content-type'),
		'ContentLength': properties.get('content-length')
	}
	return out_json

class SimpleIO(object):
	def read_int(self):
		data = ''
		n = 4
		while n > 0:
			read_data = sys.stdin.read(n)
			if 0 == len(read_data):
				raise StopIteration
			data += read_data
			n -= len(read_data)
		if data:
			return unpack('i', data)[0]
		else:
			# check eof?
			raise StopIteration
	def read_string(self):
		n = self.read_int()
		if 0 == n:
			return ''
		data = ''
		while n > 0:
			read_data = sys.stdin.read(n)
			data += read_data
			n -= len(read_data)
		if data:
			return data
		else:
			raise SystemError
	def read_json(self):
		json_str = self.read_string()
		if json_str:
			return json.loads(json_str)
		else:
			return None
	def write_int(self, val):
		data = pack('i', val)
		sys.stdout.write(data)
		sys.stdout.flush()
	def write_string(self, val):
		self.write_int(len(val))
		sys.stdout.write(val)
		sys.stdout.flush()
		# log
	def write_json(self, val):
		s = json.dumps(val)
		self.write_string(s)
	def write_exception(self, e):
		self.write_json(_convert_exception(e))

class FileObjectWithProgress(object):
	"""
	Readable file object with progress wrapper.
	"""

	def __init__(self, io):
		"""
		Wrap the underlying file object

		:param file_obj: the file object to wrap
		"""
		self._io = io
		self._file_obj = None
		self._prev_process_size = 0

	def set_file_obj(self, file_obj):
		self._file_obj = file_obj
		self._prev_process_size = 0

	def read(self, length=None):
		read_data = self._file_obj.read(length)
		self._prev_process_size += len(read_data)

		res = {
			'success': True,
			'complete': False,
			'uploaded': self._prev_process_size
		}
		if self._io:
			self._io.write_json(res)
		else:
			print res
		return read_data

	def write(self, write_data):
		self._file_obj.write(write_data)
		self._prev_process_size += len(write_data)

		res = {
			'success': True,
			'complete': False,
			'downloaded': self._prev_process_size
		}
		if self._io:
			self._io.write_json(res)
		else:
			print res
		return None
	def tell(self):
		return self._file_obj.tell();
	def seek(self, offset, whence=os.SEEK_SET):
		self._file_obj.seek(offset, whence)

class OpenStackSwiftApi(object):
	def __init__(self, io=None):
		import swiftclient

		self._file_obj_progress = FileObjectWithProgress(io)
		self._io = io
		SYNO_SOCKET_TIMEOUT = 600

		#os.environ['SWIFT_DEBUG'] = 1
		self._swift = swiftclient.Connection(
			authurl=os.environ.get('OPENSTACK_SWIFT_URL'),
			user=os.environ.get('OPENSTACK_SWIFT_USER'),
			key=os.environ.get('OPENSTACK_SWIFT_KEY'),
			retries=int(os.environ.get('OPENSTACK_SWIFT_RETRIES')),
			preauthurl=os.environ.get('OPENSTACK_SWIFT_PREAUTHURL'),
			preauthtoken=os.environ.get('OPENSTACK_SWIFT_PREAUTHTOKEN'),
			auth_version=os.environ.get('OPENSTACK_SWIFT_VERSION'),
			os_options={
				'tenant_id': os.environ.get('OPENSTACK_SWIFT_TENANT_ID'),
				'tenant_name': os.environ.get('OPENSTACK_SWIFT_TENANT_NAME'),
				'user_domain_id': os.environ.get('OPENSTACK_SWIFT_DOMAIN_ID'),
				'user_domain_name': os.environ.get('OPENSTACK_SWIFT_DOMAIN_NAME'),
				'region_name': os.environ.get('OPENSTACK_SWIFT_REGION')
			},
			timeout=SYNO_SOCKET_TIMEOUT)
		self._service_options={
			'auth': os.environ.get('OPENSTACK_SWIFT_URL'),
			'user': os.environ.get('OPENSTACK_SWIFT_USER'),
			'key': os.environ.get('OPENSTACK_SWIFT_KEY'),
			'retries': int(os.environ.get('OPENSTACK_SWIFT_RETRIES')),
			'auth_version': os.environ.get('OPENSTACK_SWIFT_VERSION'),
			'os_tenant_id': os.environ.get('OPENSTACK_SWIFT_TENANT_ID'),
			'os_tenant_name': os.environ.get('OPENSTACK_SWIFT_TENANT_NAME'),
			'os_user_domain_id': os.environ.get('OPENSTACK_SWIFT_DOMAIN_ID'),
			'os_user_domain_name': os.environ.get('OPENSTACK_SWIFT_DOMAIN_NAME'),
			'os_auth_token': os.environ.get('OPENSTACK_SWIFT_PREAUTHTOKEN'),
			'os_storage_url': os.environ.get('OPENSTACK_SWIFT_PREAUTHURL'),
			'os_region_name': os.environ.get('OPENSTACK_SWIFT_REGION')}
		self._swift_service = None

		del os.environ['OPENSTACK_SWIFT_VERSION']
		del os.environ['OPENSTACK_SWIFT_URL']
		del os.environ['OPENSTACK_SWIFT_USER']
		del os.environ['OPENSTACK_SWIFT_KEY']
		del os.environ['OPENSTACK_SWIFT_RETRIES']
		del os.environ['OPENSTACK_SWIFT_TENANT_ID']
		del os.environ['OPENSTACK_SWIFT_TENANT_NAME']
		del os.environ['OPENSTACK_SWIFT_DOMAIN_ID']
		del os.environ['OPENSTACK_SWIFT_DOMAIN_NAME']
		del os.environ['OPENSTACK_SWIFT_REGION']
		del os.environ['OPENSTACK_SWIFT_PREAUTHURL']
		del os.environ['OPENSTACK_SWIFT_PREAUTHTOKEN']
		log_debug('agent created')

	def getAuth(self, in_json):
		storage_url, token = self._swift.get_auth()

		return {
			'success': True,
			'token': token,
			'endpoint': storage_url
		}
	def getAuthInfo(self, in_json):
		storage_url, token = self._swift.get_auth_info()
		if not storage_url or not token:
			return {
				'success': False
			}
		return {
			'success': True,
			'token': token,
			'endpoint': storage_url
		}

	def getCapabilities(self, in_json):
		res = self._swift.get_capabilities()

		return {
			'success': True,
			'capabilities': res
		}

	def headAccount(self, in_json):
		headers = self._swift.head_account()

		# 404 not found
		return {
			'success': True,
			'account': headers
		}
	def listRegions(self, in_json):
		regions = self._swift.get_region()

		out_json = {
			'success': True,
			'region': []
		}
		for r in regions:
			out_json['region'].append({
				'Name': r
			})

		return out_json
	def putContainer(self, in_json):
		res = {}
		self._swift.put_container(
			container=in_json['container'],
			response_dict=res)

		code = res.get('status')
		# 201 Created
		# 202 Accepted (exist)
		# 204 Normal response
		# 400 name len > 256
		if code == 201 or code == 204:
			return {'success': True, 'error_code': code, 'error_message': res.get('reason')}
		else:
			return {'success': False, 'error_code': code, 'error_message': res.get('reason')}
	def headContainer(self, in_json):
		headers = self._swift.head_container(in_json['container'])

		# 404 not found
		return {
			'success': True,
			'LastModified': _convert_GMT_time_str(headers.get('date'))
		}
	def listContainers(self, in_json):
		headers, containers = self._swift.get_account(
			full_listing=True)

		out_json = {
			'success': True,
			'container': []
		}
		for c in containers:
			out_json['container'].append({
				'Name': c.get('name')
			})

		return out_json
	def deleteContainer(self, in_json):
		res = {}
		self._swift.delete_container(
			container=in_json['container'],
			response_dict=res)

		code = res.get('status')
		# 204 Normal response
		# 404 not found
		# 409 conflict
		if code == 204:
			return {'success': True, 'error_code': code, 'error_message': res.get('reason')}
		else:
			return {'success': False, 'error_code': code, 'error_message': res.get('reason')}
	def putObject(self, in_json):
		res = {}
		with open(in_json['fileInput'], "rb") as stream:
			self._file_obj_progress.set_file_obj(stream)
			self._swift.put_object(
				container=in_json['container'],
				obj=in_json['name'],
				contents=self._file_obj_progress,
				response_dict=res)

		code = res.get('status')
		# 201 Normal response
		# 408 timeout
		# 400 name len > 1024
		# 411 length required
		# 413 large file
		# 422 unprocessable entity
		if code == 201:
			return {'success': True, 'error_code': code, 'error_message': res.get('reason'),
					'Properties': _convert_properties_by_dict(res.get('headers'))}
		else:
			return {'success': False, 'error_code': code, 'error_message': res.get('reason')}
	def putDirectory(self, in_json):
		res = {}
		self._swift.put_object(
			container=in_json['container'],
			obj=in_json['name'],
			contents='',
			content_type='application/directory',
			response_dict=res)

		code = res.get('status')
		# 201 Normal response
		# 408 timeout
		# 400 name len > 1024
		# 411 length required
		# 413 large file
		# 422 unprocessable entity
		if code == 201:
			return {'success': True, 'error_code': code, 'error_message': res.get('reason')}
		else:
			return {'success': False, 'error_code': code, 'error_message': res.get('reason')}
	def listObjects(self, in_json):
		limit_count = 10000
		marker_obj = in_json.get('Marker', None)
		prefix_obj = in_json.get('Prefix', None)
		delimiter_obj = in_json.get('Delimiter', None)

		headers, objects = self._swift.get_container(
			container=in_json['container'],
			marker=marker_obj,
			limit=limit_count,
			prefix=prefix_obj,
			delimiter=delimiter_obj)

		targetType = in_json.get('TargetType', 'all')
		count = 0
		out_json = {
			'success': True,
			'folder': [],
			'file': []
		}

		for o in objects:
			if targetType == 'folder' or targetType == 'all':
				if o.get('subdir'):
					out_json['folder'].append({'Name': o.get('subdir')})
					count += 1
			if targetType == 'file' or targetType == 'all':
				if o.get('name'):
					out_json['file'].append({
						'Name': o.get('name'),
						'Properties': _convert_properties(o)
					})
					count += 1
		if len(objects) == limit_count:
			if o.get('name'):
				out_json['NextMarker'] = objects[limit_count - 1].get('name')
			else:
				out_json['NextMarker'] = objects[limit_count - 1].get('subdir')
		out_json['count'] = count
		return out_json
	def headObject(self, in_json):
		headers = self._swift.head_object(
			container=in_json['container'],
			obj=in_json['name'])

		properties = _convert_properties_by_dict(headers)
		if "\"" == properties['ETag'][0] and "\"" == properties['ETag'][-1]:
			properties['ETag'] = properties['ETag'][1:-1]

		return {
			'success': True,
			'Properties': properties
		}
	def deleteObject(self, in_json):
		res = {}
		self._swift.delete_object(
			container=in_json['container'],
			obj=in_json['name'],
			response_dict=res)

		code = res.get('status')
		# 204 Normal response
		# 400
		# 404 not found
		# 500
		if code == 204:
			return {'success': True, 'error_code': code, 'error_message': res.get('reason')}
		else:
			return {'success': False, 'error_code': code, 'error_message': res.get('reason')}
	def getObject(self, in_json):
		headers_obj = None
		read_len = 65536
		if in_json.get('RangeStart') and in_json.get('RangeEnd'):
			headers_obj = {'Range': 'bytes=' + in_json.get('RangeStart') + '-' + in_json.get('RangeEnd')}

		hdrs, body = self._swift.get_object(
			container=in_json['container'],
			obj=in_json['name'],
			resp_chunk_size=read_len,
			headers=headers_obj)

		with open(in_json['fileOutput'], "wb") as stream:
			self._file_obj_progress.set_file_obj(stream)
			while True:
				try:
					self._file_obj_progress.write(body.next())
				except StopIteration:
					break

		# 404 not found
		return {'success': True}
	def writeJson(self, res):
		if self._io:
			self._io.write_json(res)
		else:
			print res

	def putLargeObject(self, in_json):
		from swiftclient.service import SwiftService
		from swiftclient.service import SwiftUploadObject
		if self._swift_service is None:
			storage_url, token = self._swift.get_auth_info()
			if storage_url and token:
				self._service_options['os_auth_token'] = token
				self._service_options['os_storage_url'] = storage_url
			self._swift_service = SwiftService(self._service_options)

		generator = self._swift_service.upload(
			container=in_json['container'],
			objects=[SwiftUploadObject(
				source=in_json['fileInput'],
				object_name=in_json['name'])],
			options={
				'segment_size': in_json['segmentSize'],
				'segment_container': in_json['container']})
		for r in generator:
			if r['success']:
				if 'object' in r and 'upload_object' == r['action']:
					if 'manifest_response_dict' in r:
						return {
							'success': True,
							'error_code': r['manifest_response_dict'].get('status'),
							'error_message': r['manifest_response_dict'].get('reason'),
							'Properties': _convert_properties_by_dict(r['manifest_response_dict'].get('headers'))}
					elif 'response_dict' in r:
						return {
							'success': True,
							'error_code': r['response_dict'].get('status'),
							'error_message': r['response_dict'].get('reason'),
							'Properties': _convert_properties_by_dict(r['manifest_response_dict'].get('headers'))}
				elif 'for_object' in r:
					self.writeJson({
						'success': True,
						'complete': False,
						'segment_location': r['segment_location'],
						'segment_size': r['segment_size']})
			else:
				return _convert_exception(r['error'])

	def deleteLargeObject(self, in_json):
		from swiftclient.service import SwiftService
		if self._swift_service is None:
			storage_url, token = self._swift.get_auth_info()
			if storage_url and token:
				self._service_options['os_auth_token'] = token
				self._service_options['os_storage_url'] = storage_url
			self._swift_service = SwiftService(self._service_options)

		res = {}
		generator = self._swift_service.delete(
			container=in_json['container'],
			objects=[in_json['name']])
		for r in generator:
			if r['success']:
				if r['action'] == 'delete_object':
					return {
						'success': True,
						'error_code': r['response_dict'].get('status'),
						'error_message': r['response_dict'].get('reason')}
				#elif r['action'] == 'delete_segment':
				#elif r['action'] == 'delete_container':
			else:
				return _convert_exception(r['error'])

def start_server():
	io = SimpleIO()

	try:
		api = OpenStackSwiftApi(io)
	except Exception as e:
		io.write_exception(e)
		return False

	io.write_string('start')

	while True:
		try:
			in_json = io.read_json()
			fn_name = in_json['fn']
			fn = getattr(api, fn_name)
			del in_json['fn']

			if fn is None:
				raise SystemError('no such fn: ' + fn_name)

			#log_debug('\033[34mexecute: ' + fn_name + ' ' + json.dumps(in_json) + '\033[0m');

			res = fn(in_json)
			io.write_json(res)
		except StopIteration:
			break
		except Exception as e:
			io.write_exception(e)
			continue

if __name__ == '__main__':
	# Under window, there are text mode and binary mode for files,
	# Set binary mode before sending binary data(to stdout)
	# to prevent some unexpected behavior!
	if sys.platform == "win32":
		import os, msvcrt
		msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

	# add include path
	script_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
	sys.path.insert(0, script_dir + '/swiftclient')
	sys.path.insert(1, script_dir + '/keystoneclient')
	sys.path.insert(2, script_dir + '/module')

	res = start_server()
	sys.exit(0 if res else 1)