'''
fuzzableRequest.py

Copyright 2006 Andres Riancho

This file is part of w3af, w3af.sourceforge.net .

w3af is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.

w3af is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with w3af; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

'''

from core.controllers.w3afException import w3afException
import core.controllers.outputManager as om
from core.data.dc.dataContainer import dataContainer as dc
import core.data.kb.config as cf
from core.data.parsers.urlParser import uri2url

class fuzzableRequest:
	'''
	This class represents a fuzzable request. Fuzzable requests where created to allow w3af plugins
	to be much simpler and dont really care if the vulnerability is in the postdata, querystring, header, cookie
	or some other variable.
	
	Other classes should inherit from this one and change the behaviour of getURL() and getData(). For
	example, the class httpQsRequest should return the _dc in the querystring ( getURL ) and httpPostDataRequest
	should return the _dc in the POSTDATA ( getData() ).
	
	@author: Andres Riancho ( andres.riancho@gmail.com )
	'''

	def __init__(self):
		self._url = ''
		self._method = ''
		self._uri = ''
		self._data = ''
		
		self._createFuzzable()
		self._headers = {}
		self._cookie = {}
	
	def dump( self ):
		'''
		Return a DETAILED str representation of this fuzzable request.
		'''
		headers = None
		if 'headers' in self._fuzzable:
			headers = self._fuzzable['headers']
		else:
			headers = self._headers
		
		strRes = ''
		strRes += self._method + ' '
		strRes += self.getURI() + ' HTTP/1.1\n'
		for header in headers.keys():
			strRes += header + ': ' + headers[ header ] + '\n'
		strRes += '\n\n'
		strRes += str( self.getData() )

		return strRes
	
	def __str__( self ):
		'''
		Return a str representation of this fuzzable request.
		'''
		strRes = ''
		strRes += self._url
		strRes += ' | Method: ' + self._method
		if len(self._fuzzable['dc']):
			strRes += ' | Parameters: ('
			for i in self._fuzzable['dc'].keys():
				strRes += i + ','
			strRes = strRes[: -1]
			strRes += ')'
		return strRes		
		
	def __eq__( self, other ):
		if self._url == other._url and\
		self._method == other._method and\
		self._fuzzable['dc'] == other._fuzzable['dc']:
			return True
		else:
			return False
	
	def __ne__( self,other):
		return not self.__eq__( other )
	
	def _sanitizeURL( self, url ):
		return url.replace(' ', '%20')
		
	def setURL( self , url ):
		self._url = self._sanitizeURL( url )
	
	def setURI( self, uri ):
		self._uri = self._sanitizeURL( uri )
		self._url = self._sanitizeURL( uri2url( uri ) )
		
	def setMethod( self , method ):
		self._method = method
		
	def setDc( self , dataCont ):
		if isinstance(dataCont, dc):
			self._fuzzable['dc'] = dataCont
		else:
			raise w3afException('Invalid call to fuzzableRequest.setDc(), the argument must be a dataContainer instance.')
		
	def setHeaders( self , headers ):
		if 'headers' in self._fuzzable:
			self._fuzzable['headers'] = headers
		else:
			self._headers = headers
	
	def setReferer( self, referer ):
		if 'headers' in self._fuzzable:
			self._fuzzable['headers'][ 'Referer' ] = referer
		else:
			self._headers[ 'Referer' ] = referer
	
	def setCookie( self , cookie ):
		if 'headers' in self._fuzzable:
			self._fuzzable['cookie'] = cookie
		else:
			self._cookie = cookie			
		
	def getURL( self ):
		return self._url
	
	def getURI( self ):
		return self._uri
		
	def setData( self, d ):
		self._data = d
		
	def getData( self ):
		return self._data
		
	def getMethod( self ):
		return self._method
		
	def getDc( self ):
		return self._fuzzable['dc']
		
	def getHeaders( self ):
		if 'headers' in self._fuzzable:
			return self._fuzzable['headers']
		else:
			return self._headers
	
	def getReferer( self ):
		if 'Referer' in self._fuzzable['headers'].keys():
			if 'Referer' in self._fuzzable['headers']:
				return self._fuzzable['headers']['Referer']
		else:
			if 'Referer' in self._fuzzable['headers']:
				return self._headers['Referer']
		return ''
	
	def getCookie( self ):
		if 'cookie' in self._fuzzable:
			return self._fuzzable['cookie']
		else:
			return self._cookie
	
	def getFileVariables( self ):
		return None
	
	def _createFuzzable( self ):
		self._fuzzable = {}
		self._fuzzable['dc'] = {}
		
		tmp = {}
		for header in cf.cf.getData('fuzzableHeaders') or []:
			tmp[ header ] = ''
		
		if len( tmp.keys() ):
			self._fuzzable['headers'] = tmp
			
		fuzzCookie = cf.cf.getData('fuzzableCookie')
		if fuzzCookie:		
			self._fuzzable['cookie'] = {'Cookie':''}
	
	def getFuzzable( self ):
		return self._fuzzable
	
	def setFuzzable( self, type, value ):
		if type in ['dc','headers','cookie']:
			self._fuzzable[type] = value
		else:
			raise w3afException('Fuzzable parameters are : dc, headers, cookie.')
			
	def copy( self ):
		newFr = fuzzableRequest()
		newFr.setURL( self._url )
		newFr.setMethod( self._method )
		newFr.setDc( self._fuzzable['dc'].copy() )
		if 'headers' in self._fuzzable:
			newFr.setHeaders( self._fuzzable['headers'].copy() )
		if 'cookie' in self._fuzzable:
			newFr.setCookie( self._fuzzable['cookie'] )
		return newFr
