# Pantera - Web Pen-Test Proxy
#
# FILENAME      : panterautils.py
# CODER         : Simon Roses Femerling
# DATE          : 9/23/2004
# LAST UPDATE   : 9/04/2006
# ABSTRACT      : Python Web Pen-Test Proxy :)
#                 Pantera utils. Heavely base on SpikeProxy.
#
# - Roses Labs Innovations (RL+I)
# Roses Labs
# http://www.roseslabs.com
#
# Copyright (c) 2003-2006 Roses Labs.
#
# You may not distribute, transmit, repost this software for commercial 
# purposes without Roses Labs written permission. 
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, publish,
# distribute the Software, and to permit persons to whom the Software 
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

'''
@author:       Simon Roses Femerling
@license:      GNU General Public License 2.0 or later
@contact:      pantera.proxy@gmail.com
@organization: OWASP / Roses Labs
'''

# Pantera Utils Imports

import os
import random
import string
import cPickle
from htmllib import HTMLParser
from formatter import DumbWriter, AbstractFormatter
from cStringIO import StringIO
import re
from random import random, choice, uniform
import codecs

import pantera
import panteraLib

#############################################################################################
# Defines
#############################################################################################

YES = 1
NO  = 0
    
hd = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',]
        
#############################################################################################
# Our Functions
#############################################################################################

#############################################################################################
# FUNC     : def readuntil
# PARAMS   : mysocket, mybreakpoint
# RETURN   : Return data read or "" if none
# ABSTRACT : Read until...
def readuntil(mysocket,mybreakpoint):
    '''
    Read data until condition

    @type mysocket: socket
    @param mysocket: Socket descriptor.
    @type mybreakpoint: string
    @param mybreakpoint: string end tag.
    @return: Return string.
    '''
    data=""
    length=-len(mybreakpoint)
    #print "length=%d"%length
    while data[length:]!=mybreakpoint:
        newdata=mysocket.recv(1)
        data+=newdata
        #print "data=%s"%(data[length:])
    return data
# EOF: def reauntil

#############################################################################################
# FUNC     : def urlnormalize
# PARAMS   : url
# RETURN   : string
# ABSTRACT : Normalize URL
def urlnormalize(url):
    '''
    Normalize a URL
    
    /cow/../../../bob/bob2.php -> /bob/bob2.php    
    
    @type url: string
    @param url: String to mormalize.
    @return: Return string.
    '''
    #for win32 users
    f=url.replace("\\","/")
    if f[-1]=="/":
        tailslash=1
    else:
        tailslash=0
        
    dot=f.split("/")
    #while "." in dot:
    for i in dot:
        if i == ".":
        #print dot
            #dot=dot.remove(".")
            _=dot.pop(dot.index("."))
    while "" in dot:
        dot.remove("")
    while ".." in dot:
        firstdotdot=dot.index("..") 
        #go one directory up
        if firstdotdot==0:
            dot.remove(dot[0])
            continue
        #get rid of parent directory
        dot.remove(dot[firstdotdot-1])
        #do this again to get rid of the ..
        dot.remove(dot[firstdotdot-1])
    fin="/".join(dot)+"/"*tailslash
    if fin=="":
        fin="/"
    if fin[0]!="/":
        fin="/"+fin
    return fin
# EOF: def urlnormalize

#############################################################################################
# FUNC     : def dmkdir
# PARAMS   : newdir
# RETURN   : ...
# ABSTRACT : stolen from  http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/82465
def dmkdir(newdir):
    ''' 
    works the way a good mkdir should :)
        - already exists, silently complete
        - regular file in the way, raise an exception
        - parent directory(ies) does not exist, make them as well
        
    @type newdir: string
    @param newdir: Create directory with the give name.
    '''
    if os.path.isdir(newdir):
        pass
    elif os.path.isfile(newdir):
        raise OSError("a file with the same name as the desired " \
                      "dir, '%s', already exists." % newdir)
    else:
        head, tail = os.path.split(newdir)
        if head and not os.path.isdir(head):
            dmkdir(head)
        #print "_mkdir %s" % repr(newdir)
        if tail:
            if os.path.isdir(newdir):
                pass
            try:
                os.mkdir(newdir)
            except OSError:
                pass
# EOF: def dmkdir

#############################################################################################
# FUNC     : def joinallspaces
# PARAMS   : input
# RETURN   : string
# ABSTRACT : Joins all the spaces in a string
def joinallspaces(input):
    ''' 
    Joins all the spaces in a string. 
    
    @type input: string
    @param input: String to join spaces.
    @return: Return string.
    '''
    inputold=""
    inputnew=input[:]
    while inputold!=inputnew:
        inputold=inputnew[:]        
        inputnew=inputnew.replace("  "," ")

    return inputnew
# EOF: def joinallspaces

#############################################################################################
# FUNC     : def getrandomnumber
# PARAMS   : ...
# RETURN   : Number
# ABSTRACT : Get random number
def getrandomnumber():
    '''
    Get a random number.
    
    @return: Return number.
    '''
    return random.randrange(1,100000,1)
# EOF: def getrandomnumber

#############################################################################################
# FUNC     : def pathjoin
# PARAMS   : *paths
# RETURN   : string
# ABSTRACT : Join path
def pathjoin(*paths):
    '''
    Join path.
    
    @type *paths: list of strings
    @param *paths: List of string to join.
    @return: Return string.
    '''
    temp=""

    for path in paths:
        #print "Pathjoin "+path
        if path!="":
            if path[0]=="/" or path[0]=="\\":
                #we are windoze compliant!
                path=path[1:]
            temp=os.path.join(temp,path)
    #if the first was an absolute path...
    if paths[0][0]=="/":
        temp="/"+temp
        #add that back
        
    return temp
# EOF: def pathjoin

#############################################################################################
# FUNC     : def pathsplit
# PARAMS   : path
# RETURN   : list
# ABSTRACT : Split path
def pathsplit(path):
    '''
    Split path.
    
    @type path: string
    @param path: String to split.
    @return: Return list.
    '''
    temp=path
    last="tempval"
    retList=[]
    while last!="":
        temp,last=os.path.split(temp)
        if last!="":
            retList=[last]+retList
    return retList
# EOF: pathsplit
        
#following inits are for prettyprint
norm = string.maketrans('', '') #builds list of all characters
non_alnum = string.translate(norm, norm, string.letters+string.digits)
trans_nontext=string.maketrans(non_alnum,'#'*len(non_alnum))

#############################################################################################
# FUNC     : def prettyprint
# PARAMS   : data
# RETURN   : string
# ABSTRACT : Pretty print
def prettyprint(data):
    '''
    Pretty Print.
    
    @type data: string
    @param data: String to print.
    @return: Return string.
    '''
    cleaned=string.translate(data,trans_nontext)
    return cleaned
# EOF: def prettyprint

#############################################################################################
# FUNC     : def getURLfromFile
# PARAMS   : file
# RETURN   : string
# ABSTRACT : Open a requestandresponse object in a file and
#            obtains the url from the header
def getURLfromFile(file):
    '''
    Open a requestandresponse object in a file and obtains the url from the header.
    
    @type file: path
    @param file: Path of the file to open.
    @return: Return string.
    '''
    #load our request and response object
    infile=open(file,"rb")
    obj=cPickle.load(infile)
    infile.close()
    url=obj.clientheader.URL
    return url
# EOF: def getURLfromFile

#############################################################################################
# FUNC     : def getDirsFromURL
# PARAMS   : url
# RETURN   : list
# ABSTRACT : Takes a url like /bob/bob2/bob3/asdf.cgi
#            and returns [bob,bob2,bob3,asdf.cgi]
def getDirsFromURL(url):
    '''
    Takes a url like /bob/bob2/bob3/asdf.cgi and returns [bob,bob2,bob3,asdf.cgi]
    
    @type url: string
    @param url: String to split
    @return: Return list.
    '''
    dirList=url.split("/")
    #check for a file at the last one
    if dirList[-1].count(".")>0:
        dirList=dirList[:-1]

    #now combine them up
    start="/"
    realDirList=[]
    for dir in dirList:
        start+= "%s/" % dir 
        start=start.replace("_directory_","")
        start=start.replace("///","/")
        start=start.replace("//","/")
        realDirList.append(start)
        
    return realDirList
# EOF: def getDirsFromURL

#############################################################################################
# FUNC     : def constructRequest
# PARAMS   : myheader, mybody
# RETURN   : string
# ABSTRACT : Constructs a request given a header and optionally a body
def constructRequest(myheader,mybody=None):
    '''
    Constructs a request given a header and optionally a body.
    
    @type myheader: class
    @param myheader: HTTP header class
    @type myheader: class
    @param myheader: HTTP body class    
    @return: Return string.
    '''
    
    #for null value
    if (mybody==None):
        mybody = pantera.HTTPBody()
    
    #debug 
    if 0:
        return "GET / HTTP/1.1\r\nHost: www.roseslabs.com\r\nContent-Length: 0\r\n\r\n"

    request="%s %s%s" % (myheader.verb,myheader.getProxyHeader(),myheader.URL)
    #if we have arguments
    if myheader.useRawArguments:
        if len(myheader.allURLargs) > 0:
            request+= "?%s" % myheader.allURLargs
    else:
        if len(myheader.URLargsDict) > 0:
            request+="?"
            request+=joinargs(myheader.URLargsDict,orderlist=myheader.orderlist)
                
    request+=" %s\r\n" % myheader.version
    #ok, the first line is done!
    
    #do the rest of the headers that need order
    #I dunno if any except Host really need ordering, but I do it
    #to erase any chance of lame bugs later on
    #plus, python makes it quite easy
    needOrdered=["Host","User-Agent","Accept","Accept-Language","Accept-Encoding","Accept-Charset","Keep-Alive","Connection","Pragma","Cache-Control"]
    for avalue in needOrdered:
        request+=myheader.grabHeader(avalue)
    #now work on the header pairs we haven't already done
    for akey in myheader.headerValuesDict.keys():
        if akey not in needOrdered:
            request+=myheader.grabHeader(akey)

    #ok, headers are all done except for content-length
    #Content-Length: 0 should always be valid, but it's
    #not working for some reason on get requests!
    if mybody.mysize!=0 or myheader.verb!="GET":
        r = len(mybody.data)
        if not myheader.surpressContentLength() or r != 0:
            request+="Content-Length: %s\r\n" % str(len(mybody.data))

    #ok, all headers are done, finish with blank line
    request+="\r\n"

    #ok, now add body
    request+="".join(mybody.data)

    #done!
    return request
# EOF: def constructRequest

#############################################################################################
# FUNC     : def joinargs
# PARAMS   : argdict, orderlist
# RETURN   : string 
# ABSTRACT : Takes in a dict, returls A=B&C=D,etc
def joinargs(argdict,orderlist=[]):
    '''
    Takes in a dict, returls A=B&C=D,etc
    
    @type argdict: dict
    @param argdict: Dict.
    @type orderlist: list
    @param orderlist: Follow order.
    @return: Return string.
    '''
    first=1
    result=""
    donelist=[]
    for akey in orderlist:
        donelist.append(akey)
        if not first:
            result+="&"
        first=0
        result+= "%s=%s" % (akey,argdict[akey])

    for akey in argdict.keys():
        if akey in donelist:
            continue
        if not first:
            result+="&"
        first=0
        result+= "%s=%s" % (akey,argdict[akey])

    return result
# EOF: def joinargs(

#############################################################################################
# FUNC     : def splitargs
# PARAMS   : argstring, orderlist
# RETURN   : dict on succes or none on error
# ABSTRACT : Returns a dictionary of a string split like a normal HTTP argument list
def splitargs(argstring,orderlist=[]):
    '''
    Returns a dictionary of a string split like a normal HTTP argument list.
    
    @type argstring: string
    @param argstring: String argument.
    @type orderlist = list
    @param orderlist: Follow order.
    @return: Return string.
    '''
    resultDict={}
    templist=argstring.split("&")
    for pair in templist:
        if pair!="":
            templist2=pair.split("=")
            if len(templist2)<2:
                #print "Failed to parse the URL arguments because of
                #invalid number of equal signs in one argument in:
                #\""+pair+"\" len="+str(len(templist2))
                return None
            else:
                #add this argument to the Dict
                orderlist.append(templist2[0])
                resultDict[templist2[0]]="=".join(templist2[1:])
    return resultDict
# EOF: def splitargs

#############################################################################################
# FUNC     : def splitstring
# PARAMS   : astring
# RETURN   : list
# ABSTRACT : Turns a string into a one character list
def splitstring(astring):
    '''
    Turns a string into a one character list.
        
    @type astring = list
    @param astring: String to convert into a list.
    @return: Return string.
    '''
    alist = [ch for ch in astring]
    return alist
# EOF: def splitstring

#############################################################################################
# FUNC     : def printFormEntry
# PARAMS   : text, name, value
# RETURN   : string
# ABSTRACT : Print a form entry
def printFormEntry(text, name,value, inside_table=0, size=15):
    '''
    Print a form entry.
    
    @type text: string
    @param text: String to display.
    @type name: string
    @param name: Name of the input tag.
    @type inside_table: int
    @param inside_table: If 0 input tag inside html table, else if 1 input is not in html table.
    @type size: int
    @param size: Size of the input tag.
    @return: Return string.
    '''
    if inside_table==1:
        result= "<td>%s:</td><td><input type=\"text\" name=\"%s\" value=\"%s\" size=\"%s\"></td>\r\n" % (text, name, value, str(size)) 
    else:
        result= "%s: </td><td><input type=\"text\" name=\"%s\" value=\"%s\" size=\"%s\">\r\n" % (text, name, value, str(size))  
    return result
# EOF: def printFormEntry

#############################################################################################
# FUNC     : def printFormEntryAndValue
# PARAMS   : name, key, value, file
# RETURN   : string
# ABSTRACT : Here is where you would add actions that you want to take when
#            you have an argument or variable (on the rewrite request page)
def printFormEntryAndValue(name,key,value,inside_table=0, size=15):
    '''
    Here is where you would add actions that you want to take when you have an argument or variable (on the rewrite request page)
    
    @type name: string
    @param name: Name of the input tag.
    @type key: string
    @param key: Key of input tag.
    @type value: string
    @param value: Value of input tag.
    @type inside_table: int
    @param inside_table: If 0 input tag inside html table, else if 1 input is not in html table.
    @type size: int
    @param size: Size of the input tag.
    @return: Return string.
    '''
    result=""
    if inside_table==1:
        result+= "<td>%s:</td><td><input type=\"text\" name=\"%sN\" value=\"%s\" size=\"%s\"> :</td>\r\n" % (name,name, key, str(size)) 
        result+= "<td><input type=\"text\" name=\"%sV\" value=\"%s\" size=\"%s\"></td>" % (name,value,str(size))   
    else:
        result+= "%s: <input type=\"text\" name=\"%sN\" value=\"%s\" size=\"%s\"> : " % (name, name, key, str(size))
        result+= "<input type=\"text\" name=\"%sV\" value=\"%s\" size=\"%s\">" % (name, value, str(size))
        result+= "<br>\n"    
    return result
# EOF: def printFormEntryAndValue

#############################################################################################
# FUNC     : def printFormCheckbox 
# PARAMS   : name, checked
# RETURN   : string
# ABSTRACT : Print a checkbox form
def printFormCheckbox(text, name,checked, inside_table=0, size=15):
    '''
    Print a checkbox form.
    
    @type text: string
    @param text: String to display.
    @type name: string
    @param name: Name of the input tag.
    @type checked: string
    @param checked: Set input check.
    @type inside_table: int
    @param inside_table: If 0 input tag inside html table, else if 1 input is not in html table.
    @type size: int
    @param size: Size of the input tag.
    @return: Return string.
    '''
    """ printFormCheckbox func """
    result=""
    if inside_table==1:
        result+= "<td>%s:</td><td><input type=\"checkbox\" name=\"%s\" value=\"yes\" size=\"%s\" " % (text, name, str(size))
        if checked:
            result+= "CHECKED"
        result+= "></td>\r\n"
    else:
        result+= "%s: <input type=\"checkbox\" name=\"%s\" value=\"yes\" size=\"%s\" " % (text, name, str(size))
        if checked:
            result+= "CHECKED"
        result+= "><br>\n"
    return result
# EOF: def printFormCheckbox

#############################################################################################
# FUNC     : def printFormCheckboxValue 
# PARAMS   : name, checked
# RETURN   : string
# ABSTRACT : Print a checkbox form
def printFormCheckboxValue(text, name,value,checked, inside_table=0, size=15):
    '''
    Print a checkbox form.
    
    @type text: string
    @param text: String to display.
    @type name: string
    @param name: Name of the input tag.
    @type value: string
    @param value: Value of input tag.    
    @type checked: string
    @param checked: Set input check.
    @type inside_table: int
    @param inside_table: If 0 input tag inside html table, else if 1 input is not in html table.
    @type size: int
    @param size: Size of the input tag.
    @return: Return string.
    '''
    result=""
    if inside_table==1:
        result+= "<td>%s:</td><td><input type=\"checkbox\" name=\"%s\" value=\"%s\" size=\"%s\" " % (text, name, value, str(size))
        if checked:
            result+= "CHECKED"
        result+= "></td>\r\n"
    else:
        result+= "%s: <input type=\"checkbox\" name=\"%s\" value=\"%s\" size=\"%s\" " % (text, name, value, str(size))
        if checked:
            result+= "CHECKED"
        result+= "><br>\n"
    return result
# EOF: def printFormCheckbox

#############################################################################################
# FUNC     : def printHiddenEntry
# PARAMS   : name, value
# RETURN   : string
# ABSTRACT : Print hidden entry
def printHiddenEntry(name,value, inside_table=0):
    '''
    Print hidden entry.
    
    @type name: string
    @param name: Name of the input tag.
    @type value: string
    @param value: Value of input tag.    
    @type inside_table: int
    @param inside_table: If 0 input tag inside html table, else if 1 input is not in html table.
    @return: Return string.
    '''
    result=""
    if inside_table==1:
        result+= "<td><input type=\"hidden\" name=\"%s\" value=\"%s\"></td>\r\n" % (name, value)
    else:
        result+= "<input type=\"hidden\" name=\"%s\" value=\"%s\">\r\n" % (name, value)
    return result
# EOF: def printHiddenEntry

#############################################################################################
# FUNC     : def printFormSelectMenu
# PARAMS   : string, string, dict, value
# RETURN   : string
# ABSTRACT : print select menu to use in a form
def printFormSelectMenu(text, name, dict, inside_table=0):
    '''
    Print select menu to use in a form.
        
    @type text: string
    @param text: String to display.
    @type name: string
    @param name: Name of the input tag.
    @type dict: dict
    @param dict: Dict to use in select tag.
    @type inside_table: int
    @param inside_table: If 0 input tag inside html table, else if 1 input is not in html table.
    @return: Return string.
    '''
    result = ""
    if inside_table==1:
        result+= "<td>%s</td><td>" % text
        result+= "<SELECT NAME=\"%s\">\r\n" % name
        for d in dict:
            result+= "<OPTION value=\"%s\">%s</OPTION>\r\n" % (d,d)
        result+= "</SELECT>\r\n"
        result+= "</td>\r\n"
    else:
        result+= "<p>%s" % (text)
        result+= "<SELECT NAME=\"%s\">\r\n" % name
        for d in dict:
            result+= "<OPTION value=\"%s\">%s</OPTION>\r\n" % (d,d)
        result+= "</SELECT>\r\n"
        result+= "</p>\r\n"
    return result
# EOF: def printFormSelectMenu

#############################################################################################
# FUNC     : def printFormSelectMenuID
# PARAMS   : string, string, dict, value
# RETURN   : string
# ABSTRACT : print select menu with ID to use in a form
def printFormSelectMenuID(text, name, dict, inside_table=0):
    '''
    Print select menu with ID to use in a form.
    
    @type text: string
    @param text: String to display.
    @type name: string
    @param name: Name of the input tag.
    @type dict: dict
    @param dict: Dict to use in select tag.
    @type inside_table: int
    @param inside_table: If 0 input tag inside html table, else if 1 input is not in html table.
    @return: Return string.
    '''
    result = ""
    if inside_table==1:
        result+= "<td>%s</td><td>" % text
        result+= "<SELECT NAME=\"%s\">\r\n" % name
        for k,v in dict:
            result+= "<OPTION value=\"%s\">%s</OPTION>\r\n" % (str(k),v)
        result+= "</SELECT>\r\n"
        result+= "</td>\r\n"
    else:
        result+= "<p>%s" % text
        result+= "<SELECT NAME=\"%s\">\r\n" % name
        for k,v in dict:
            result+= "<OPTION value=\"%s\">%s</OPTION>\r\n" % (str(k),v)
        result+= "</SELECT>\r\n"
        result+= "</p>\r\n"
    return result
# EOF: def printFormSelectMenuID

#############################################################################################
# FUNC     : def headerdictcmp
# PARAMS   : dict1, dict2
# RETURN   : Return 1 if they are the same, 0 if not
# ABSTRACT : Filters out Date: and whatnot
#            this is basically to detect if we get different Cookies
#            this is lame, but it should work ok
def headerdictcmp(dict1,dict2):
    '''
    Filters out Date: and whatnot this is basically to detect if we get different Cookies
    this is lame, but it should work ok
    
    @type dict1: dict
    @param dict1: First dict.
    @type dict2: dict
    @param dict2: Second dict.
    @return: Return 0 if they are different, else 1.    
    '''
    for akey in dict1.keys():
        if akey=="Date":
            continue
        if not dict2.has_key(akey):
            return 0
        for bkey in dict1[akey]:
            if not bkey in dict2[akey]:
                return 0
    return 1
# EOF: def headerdictcmp

#############################################################################################
# FUNC     : def genhash
# PARAMS   : clientheader, clientbody, serverheader, serverbody
# RETURN   : string
# ABSTRACT : Hashes a requestandresponse so we can do matches quickly
#            returns a string as the hash
def genhash(clientheader,clientbody,serverheader,serverbody):
    '''
    Hashes a requestandresponse so we can do matches quickly returns a string as the hash

    @type  clientheader: class
    @param clientheader: Contains a HTTP header class.
    @type  clientbody: class
    @param clientbody: Contains a HTTP body class.
    @type  serverheader: class
    @param serverheader: Contains a HTTP body class.
    @type  serverbody: class
    @param serverbody: Contains a HTTP body class.
    @return: Return string hash.    
    '''
    #print "in genhash"
    CH=clientheader.genhash()
    CB=clientbody.genhash()
    SH=serverheader.genhash()
    SB=serverbody.genhash()
    return CH+CB+SH+SB
# EOF: def genhash

#############################################################################################
# FUNC     : def hashstring
# PARAMS   : astring
# RETURN   : string
# ABSTRACT : Hashes a string to a number, then returns that number as a string
def hashstring(astring):
    '''
    Hashes a string to a number, then returns that number as a string.
    
    @type astring: string
    @param astring: String to hash.
    @return: Return string.    
    '''
    i=0
    #print "in hashstring"
    if astring=="":
        return ""

    hashnum=0
    l=len(astring)
    while i<l:
        hashnum+=ord(astring[i])*2
        i=i+1

    return str(hashnum)
# EOF: def hashstring

#############################################################################################
# FUNC     : def strencode
# PARAMS   : astring, sepchar
# RETURN   : string
# ABSTRACT : String encode
def strencode(astring,sepchar="_"):
    '''
    String encode.
    
    @type astring: string
    @param astring: String to encode.
    @type sepchar: string
    @param sepchar: String to be use as separator.    
    @return: Return string.    
    '''
    temp=astring.replace(":",sepchar)
    temp=temp.replace("/",sepchar)
    temp=temp.replace("\\",sepchar)
    #should we replace _ here as well?
    return temp
# EOF: def strencode

#############################################################################################
# FUNC     : def constructResponse
# PARAMS   : myheader, mybody
# RETURN   : string
# ABSTRACT : Construct a response
def constructResponse(myheader,mybody):
    '''
    Construct a response.
    
    @type myheader: class
    @param myheader: Contains a HTTP header class.
    @type  mybody: class
    @param mybody: Contains a HTTP body class.
    @return: Return string.    
    '''
    if myheader.firstline=="":
        print "Serious error: response's first line is empty!"
        print "Full response: %s" % str(myheader.data)
            
    response = "%s\r\n" % myheader.firstline

    needOrdered=["Server"]
    slist = [myheader.grabHeader(avalue) for avalue in needOrdered]
    response += "".join(slist)
     
    for akey in myheader.headerValuesDict.keys():
        #don't send 2 Content-lengths
        if akey not in [ "Content-Length", "Content-length"]:
            if akey not in needOrdered:
                response+=myheader.grabHeader(akey)

    #this may be lame and need to be taken out, but I want people to know.
    response+= "Content-Length: %s\r\n" % str(mybody.mysize)
                
    response+="\r\n"
    response+="".join(mybody.data)
    return response
# EOF: def constructResponse

#############################################################################################
# FUNC     : def JustConstructResponse
# PARAMS   : myheader, mybody
# RETURN   : string
# ABSTRACT : Construct a response
def JustConstructResponse(myheader,mybody):
    '''
    Construct a response.
    
    @type myheader: class
    @param myheader: Contains a HTTP header class.
    @type mybody: class
    @param mybody: Contains a HTTP body class.
    @return: Return string.    
    '''
    if myheader.firstline=="":
        print "Serious error: response's first line is empty!"
        print "Full response: %s" % str(myheader.data)
            
    response = "%s\r\n" % myheader.firstline

    needOrdered=["Server"]
    slist = [myheader.grabHeader(avalue) for avalue in needOrdered]
    response += "".join(slist)
     
    for akey in myheader.headerValuesDict.keys():
        #don't send 2 Content-lengths
        if akey not in [ "Content-Length", "Content-length"]:
            if akey not in needOrdered:
                response+=myheader.grabHeader(akey)

    #this may be lame and need to be taken out, but I want people to know.
    response+= "Content-Length: %s\r\n" % str(mybody.mysize)
                
    response+="\r\n"
    return response
# EOF: def JustConstructResponse

#############################################################################################
# FUNC     : constructResponseJS
# PARAMS   : header data, body data
# RETURN   : string
# ABSTRACT : Construct response for JS
def constructResponseJS(myheader,mybody):
    '''
    Construct response for JS.
    
    @type myheader: class
    @param myheader: Contains a HTTP header class.
    @type mybody: class
    @param mybody: Contains a HTTP body class.
    @return: Return string.    
    '''
    if myheader.firstline=="":
        print "Serious error: response's first line is empty!"
        print "Full response: %s" % str(myheader.data)
            
    response= "%s\\r\\n\"+\r\n" % myheader.firstline

    needOrdered=["Server"]
    igrab = myheader.igrabHeader
    for avalue in needOrdered:
        res = igrab(avalue)
        if res == "":
            response+= "\"\"+\r\n"
        else:
            if res.count('"')>0: # catch " sign inside, some headers have " inside, so we need to deal with them
                res = string.replace(res,'\n',' ') # we need all these replaces as some sites send weirds headers..
                res = string.replace(res,'\t',' ')
                res = string.replace(res,'\r\n',' ')
                response+= "\"%s\\r\\n\"+\r\n" % FixString(res)
            else:
                res = string.replace(res,'\n',' ') # we need all these replaces as some sites send weirds headers..
                res = string.replace(res,'\t',' ')
                res = string.replace(res,'\r\n',' ')
                response+= "\"%s\\r\\n\"+\r\n" % res
        
    igrab = myheader.igrabHeader
    for akey in myheader.headerValuesDict.keys():
        #don't send 2 Content-lengths
        if akey not in [ "Content-Length", "Content-length"]:
            if akey not in needOrdered:
                z = ""
                z = igrab(akey)
                if z.count('"')>0: # catch " sign inside, some headers have " inside, so we need to deal with them
                    z = string.replace(z,'\n',' ') # we need all these replaces as some sites send weirds headers..
                    z = string.replace(z,'\t',' ')
                    z = string.replace(z,'\r\n',' ')
                    response+= "\"%s\\r\\n\"+\r\n" % FixString(z)
                else:
                    z = string.replace(z,'\n',' ')
                    z = string.replace(z,'\t',' ')
                    z = string.replace(z,'\r\n',' ')
                    response+="\"%s\\r\\n\"+\r\n" % z

    #this may be lame and need to be taken out, but I want people to know.
    response+= "\"Content-Length: %s\\r\\n" % str(mybody.mysize)
            
    return response
# EOF: def constructResponseJS

#############################################################################################
# FUNC     : def daveFormParse
# PARAMS   : page
# RETURN   : list
# ABSTRACT : Returns a list of urls with arguments we've parsed from the page
#            very kludgy function
def daveFormParse(page):
    '''
    Returns a list of urls with arguments we've parsed from the page very kludgy function.
    
    @type page: string
    @param page: String to be parser.
    @return: Return list.    
    '''
    formList=[]
    resultList=[]

    debug_daveformparse=0

    if debug_daveformparse:
        print "ENTERED FORM PARSER"
    #split the forms out
    formList=page.split("<form")
    for form in formList:
        if debug_daveformparse:
            print "Handling form: "+form[:50]
        match=" action"
        if form[:len(match)].lower() not in [match]:
            continue
        index=form.find("action=\"")+8
        if index==-1:
            index=form.find("ACTION=\"")+8
            if index==-1:
                continue
        #if find is bugging out on you, upgrade python
        index2=form.find("\"",index+1)
        if index2==-1:
            continue
        url=form[index:index2]
        index2=form.find("/form>")
        if index2==-1:
            continue
        form=form[:index2]
        if debug_daveformparse:
            print "***Form Url is "+url
        argsDict={}
        inputList=form.split("<input")
        for input in inputList:
            input=joinallspaces(input)
            if debug_daveformparse:
                print "Parsing input %s" % input
            spacessplit=input.split(" ")
            name=""
            value=""
            type=""
            for entry in spacessplit:
                if debug_daveformparse:
                    print "Parsing entry"+entry
                if entry[:len("name=\"")]=="name=\"":
                    name=entry.replace("name=\"","")
                    index=name.find("\"")
                    name=name[:index]
                elif entry[:len("value=\"")]=="value=\"":
                    value=entry.replace("value=\"","")
                    index=value.find("\"")
                    value=value[:index]
                elif entry[:len("type=\"")]=="type=\"":
                    type=entry.replace("type=\"","")
                    index=type.find("\"")
                    type=type[:index]
            
            if debug_daveformparse:
                print "Name="+name+" Value="+value+" type="+type

            if name!="" and type!="submit":
                argsDict[name]=value
        if debug_daveformparse:
            print "Found form: %s?%s"  % (url,joinargs(argsDict))
        resultList.append("%s?%s" % (url,joinargs(argsDict)))

    return resultList
# EOF: def daveFormParse

#############################################################################################
# FUNC     : def rawParse
# PARAMS   : page
# RETURN   : list
# ABSTRACT : Raw parse
def rawParse(page):
    '''
    Raw parser.
    
    @type page: string
    @param page: String to be parser.
    @return: Return list.    
    '''
    results=[]
    debug_rawparse=0
    if debug_rawparse:
        print "Entered rawparse"
    list=page.split("href=")
    for file in list:
        if file[0]!="\"":
            continue
        file=file[1:255]
        #print "Parsing file %s" % file
        index=file.find("\"")
        if index==-1:
            continue
        newurl=file[:index]
        if debug_rawparse:
            print "newurl=%s" % newurl
        results.append(newurl)
    return results
# EOF: def rawParse

#############################################################################################
# FUNC     : def collectURLSFromPage
# PARAMS   : page
# RETURN   : list
# ABSTRACT : Takes in the page as a string, then returns a list of URLS
#            eventally this will do forms as well. :>
def collectURLSFromPage(page):
    '''
    Takes in the page as a string, then returns a list of URLS eventally this will do forms as well. :>
    
    @type page: string
    @param page: String to be parser.
    @return: Return list.    
    '''
    
    resultList=[]

    #print "Doing form parser"
    if page.count("<form")>0:
        otherlist=daveFormParse(page)
        for key in otherlist:
            resultList.append(key)
            pass

    #print "Doing RAW Parser"
    spamList=rawParse(page)
    for key in spamList:
        resultList.append(key)
        pass

    #the whole "AbstractFormater()" line is a bunch of crap I copied
    #That needs to be documented somehow, but I have no idea what it does
    try:
        parser=HTMLParser(AbstractFormatter(DumbWriter(StringIO())))
        parser.feed(page)
        parser.close()
        
    except:
        #print "DEBUG: Caught an exception trying to parse that html file."
        #print "(Not sure why this happens - you'll have to crawl this page manually)"
        return resultList

    #print "Adding HTML Parser data"
    for key in parser.anchorlist:
        resultList.append(key)
        pass
            
    return resultList
# EOF: def collectURLSFromPage

#############################################################################################
# FUNC     : def Str2List
# PARAMS   : string, splitter
# RETURN   : list
# ABSTRACT : Convert a string to a list
def Str2List(str1,splitter=","):
    '''
    Convert a string to a list

    @type str1: string
    @param str1: String to be converted.
    @type splitter: string
    @param splitter: String to be used as separator.
    @return: Return list.    
    '''
    d = []
    d = str1.split(splitter)
    return d
# EOF: def Str2List

#############################################################################################
# FUNC     : def List2Str
# PARAMS   : list, splitter
# RETURN   : string
# ABSTRACT : Convert a list to a string
def List2Str(l,splitter=""):
    '''
    Convert a list to a string
    
    @type l: list
    @param l: List to be converted.
    @type splitter: string
    @param splitter: String to be used as separator.
    @return: Return list.    
    '''
    s = ""
    c = 0
    for d in l:
        if c == 0: # ugly but should do
            s += str(d)
        else:
            s += splitter + str(d)
        c += 1
    return s
# EOF: def List2Str

#############################################################################################
# FUNC     : def FixString
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Fix a string to be displayed
def FixString(t):
    '''
    Fix a string to be displayed.
    
    @type t: string
    @param t: String to be displayed.
    @return: Return list.    
    '''
    c_h = ""
    slen = t.count('"')
    t1 = string.split(t,'"')
    i = 0
    for c in t1:
        c_h += c
        if i < slen:
            c_h += "\\\""
        i+=1
    return c_h
# EOF: def FixString

#############################################################################################
# FUNC     : def encode_hex 
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Encode a string to hex
def encode_hex(istr):
    '''
    Encode a string to hex
    
    @type istr: string
    @param istr: String to be encoded.
    @return: Return string.    
    '''
    strt = ""
    con = "%%%02x"
    for c in istr:
        if c == '/':
            continue
        strt += con % ord(c)
    return strt
# EOF: def encode_hex

#############################################################################################
# FUNC     : def encode_hex_random 
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Encode a string to hex randomly
def encode_hex_random(istr):
    '''
    Encode a string to hex randomly.
    
    @type istr: string
    @param istr: String to be encoded.
    @return: Return string.        
    '''
    strt = ""
    con = "%%%02x"
    for c in istr:
        if c == '/':
            continue
        i = int(uniform(0,10))
        i = i % 2
        if i == 1:
            strt += con % ord(c)
        else:
            strt += c
    return strt
# EOF: def encode_hex_random

#############################################################################################
# FUNC     : def encode_anti_ids
# PARAMS   : string, value
# RETURN   : string
# ABSTRACT : Encode a string for Anti-IDS :)
def encode_anti_ids(uri, mode = ""):
    '''
    Encode a string for Anti-IDS :)
    
    @type uri: string
    @param uri: URI to be encoded.
    @type mode: string
    @param mode: Mode as the URI will be encoded. (1-7)
    @return: Return string.    
    '''
    m = 0
    ENCODED = 0
    
    #print uri    
    
    # mode 4 - prepend long random string
    if '4' in mode:
        s = ''
        if re.match('^/',uri):
            while(len(s) < 512):
                x = randstr()
                s += x
            uri= "/%s/..%s" % (s, uri)

    # mode 7  - (windows) random case sensitivity
    if '7' in mode:
        strt = ""
        t = string.split(uri,'/')
        i = len(t)
        z = 0
        for str in t:
            for c in str:
                x = int(uniform(0,10))
                x = x % 2
                if x == 1:
                    strt += c.upper()
                else:
                    strt += c
            if z < i-1:
                strt += "/"
                z = z + 1
            uri = strt
                
    # mode 2 - directory self-reference (/./)
    if '2' in mode:
        str = uri
        p = re.compile('/')
        str = p.sub('/./', str)
        uri = str

    # mode 8 - windows directory separator (\)
    if '8' in mode:
        str = uri
        p = re.compile('/')
        str = p.sub('\\\\', str)
        p = re.compile('^\\\\')
        str = p.sub('/', str)
        p = re.compile('^(http|file|ftp|nntp|news|telnet):\\\\\\\\',re.IGNORECASE)
        str = p.sub('://', str)
        p = re.compile('\\\\$')
        str = p.sub('/', str)
        uri = str

    # mode 1 - random URI (non-UTF8) encoding
    if '1' in mode:
        if ENCODED == 0:
            uri = encode_hex_random(uri)
            ENCODED = 1

    # mode 5 - fake parameter
    if '5' in mode:
        s = randstr()
        y = randstr()
        uri = "/"+s+".html%3f"+y+"=/../"+uri   

    # mode 3 - premature URL ending
    if '3' in mode:
        s = randstr()
        uri = "/%20HTTP/1.1%0D%0A%0D%0AAccept%3A%20"+s+"/../.."+uri

    # mode 6 - TAB as request spacer
    if '6' in mode:
        uri = "\\t%s" % uri

    return uri
# EOF: def encode_anti_ids
    
#############################################################################################
# FUNC     : def randstr
# PARAMS   : value, string
# RETURN   : string
# ABSTRACT : Return a string value len with random chars
def randstr(drift = 10, chars = None):
    '''
    Return a string value len with random chars.
    
    @type drift: int
    @param drift: Number of chars to be return.
    @type chars: None or string
    @param chars: Character set to be used.
    @return: Return string.        
    '''
    str = ""
    
    if chars == None:
        chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

    while drift > 0:
        ch = choice(chars)
        str += ch
        drift = drift - 1

    return str        
# EOF: def randstr

#############################################################################################
# FUNC     : def TruncateURL
# PARAMS   : string, value
# RETURN   : string
# ABSTRACT : Truncate a URL
def TruncateURL(u, n=100):
    '''
    Truncate URL.
    
    @type u: string
    @param u: URI to be truncated.
    @type n: int
    @param n: Length of URI to be truncated.
    @return: Return string.        
    '''
    s = len(u)
    if s > n:
        n = n-3
        t = u[:n]
        t += "..."
        return t
    else:
        return u
# EOF: def TruncateURL

#############################################################################################
# FUNC     : def FilterBadCard
# PARAMS   : string, value
# RETURN   : string
# ABSTRACT : Filter bad chars in string
def FilterBadCar(s="",mode=0):
    '''
    Filter bad chars in string
    
    @type s: string
    @param s: String to be filter out.
    @type mode: int
    @param mode: Select which mode to filter. 1) filter out 2) HTML encoding
    @return: Return string.        
    '''
    # we dont allow: <>;-'%;,()#&+"*
    if mode==0:
        p = re.compile('[\<\>\;\-\'\%\;\,\(\)\#\&\+\"\*]+')
        strx = p.sub('',s)
    else:
        s = s.replace("&", "&amp;")
        s = s.replace("<", "&lt;")
        strx = s.replace(">", "&gt;")
        #strx = s.replace('"', "&quot;")
        
    return strx
# EOF: def FilterBadCar

#############################################################################################
# FUNC     : def hex2str
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Convert hex string to text string. Ripped from NTLM Proxy
def hex2str(hex_str):
    '''
    Convert hex string to text string. Ripped from NTLM Proxy.
    
    @type hex_str: string
    @param hex_str: Hex string to be converted. 
    @return: Return string.        
    '''
    res = ''
    for i in range(0, len(hex_str), 2):
        res = res + (chr(hd.index(hex_str[i]) * 16 + hd.index(hex_str[i+1])))
    return res
# EOF: def hex2str

#############################################################################################
# FUNC     : defstr2unicode
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Convert string to unicode. Ripped from NTLM Proxy
def str2unicode(string):
    '''
    Converts ascii string to dumb unicode. Ripped from NTLM Proxy.

    @type string: string
    @param string: String to be converted. 
    @return: Return string.            
    '''
    res = ''
    for i in string:
        res = res + i + '\000'
    return res
# EOF: str2unicode
    
#############################################################################################
# FUNC     : utils_split_dir
# PARAMS   : uri, mode
# RETURN   : None on error, a list on success
# ABSTRACT : Split the URI into a list of dirs
def utils_split_dir(uri = None, mode = 1):
    '''
    Split the URI into a list of dirs
    
    @type uri: string
    @param uri: String to be spittled.
    @type mode: int
    @param mode: If 1 put / after dir, else put / in front of dir.
    @return: Return list.        
    '''
    uri_split = []

    if uri == None:
        return None

    i = uri.count('/')
    if (i  >=  0):
        for z in range(i):
            str,uri = uri.split('/',1)
            if str != "":
                if mode == 1:       # Put / after dir
                    str += '/'
                if mode == 2:       # Put / in front of dir
                    t = ""
                    t += '/' + str
                    str = ""
                    str = t
                uri_split.append(str)   # mode != 1 or 2, no /
        return uri_split
    else:
        return None
# EOF: def utils_split_dir       

#############################################################################################
# FUNC     : SearchPattern
# PARAMS   : string, list, regex options
# RETURN   : Return 1 or 0
# ABSTRACT : Split the URI into a list of dirs    
def SearchPattern(my_string, l = [], re_ = re.IGNORECASE | re.MULTILINE):
    '''
    Split the URI into a list of dirs
    
    @type my_string: string
    @param my_string: String to be searched.
    @type l: list
    @param l: List of string to search for.
    @type re_: Regex options
    @param re_: Regex Options (re.IGNORECASE, etc.)
    @return: Return 1 on pattern found, else 0.  
    '''
    for i in l:
        p = re.compile(i,re_)
        r = p.search(my_string)
        if r:
            return 1
    return 0
# EOF: def SearchPattern

#############################################################################################
# FUNC     : SearchSensibleWords
# PARAMS   : string, string, regex options
# RETURN   : list
# ABSTRACT : Search sensible words in text data.       
def SearchSensibleWords(data, file='sensible_words.xml', re_ = re.IGNORECASE | re.MULTILINE):
    '''
    Search sensible words in text data.       
    
    @type data: string
    @param data: data to be searched.
    @type file: string
    @param file: XML file.
    @type re_: Regex options
    @param re_: Regex Options (re.IGNORECASE, etc.)    
    @return: list  
    '''
    l = []
    
    # Get XML file data
    xmlp = panteraLib.SensibleWordsParser()
    fil = pathjoin(os.getcwd(),"data")
    xmlp.SetFileName(pathjoin(fil,file))
    res = xmlp.BeginParser()
    if res != 0:
        return -1
    words_l = xmlp.ReturnData()
    add = l.append
    for i in words_l:
        name,re_str = i
        p = re.compile(re_str,re_)
        r = p.findall(data)
        if r:
            for c in r:
                s = "%s (%s)" % (name,str(c)) 
                add(s)
    return l        
# EOF: def SearchSensibleWords

#############################################################################################
# FUNC     : FixStringForXML
# PARAMS   : string, int
# RETURN   : string
# ABSTRACT : Fix text string to be used in XML file.
def FixStringForXML(s='', mode=0):
    '''
    Fix text string to be used in XML file.
    
    @type s: string
    @param s: String to be fixed.
    @type mode: int
    @param mode: Mode to apply.
    @return: string
    '''
    strx = ''

    if mode == 1:
        s = s.replace("&amp;", "&")
        s = s.replace("&lt;", "<")
        s = s.replace("&gt;", ">")
        strx = s.replace('&quot;', '"')
    else: # mode 0
        s = s.replace("&", "&amp;")
        s = s.replace("<", "&lt;")
        s = s.replace(">", "&gt;")
        strx = s.replace('"', "&quot;")
    
    return strx
# EOF: def FixStringForXML

#############################################################################################
# FUNC     : quoteattr
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Escape and quote an attribute value. Ripped from saxutils.py 
def quoteattr(data):
    '''
    Escape and quote an attribute value.

    Escape &, <, and > in a string of data, then quote it for use as
    an attribute value.  The \" character will be escaped as well, if
    necessary.

    You can escape other strings of data by passing a dictionary as
    the optional entities parameter.  The keys and values must all be
    strings; each key will be replaced with its corresponding value.
    
    Ripped from saxutils.py 
    
    @type data: string
    @param data: Data to be escaped and quoted.
    @return: string  
    '''
    data = FilterBadCar(data,1)
    if '"' in data:
        if "'" in data:
            data = '%s' % data.replace('"', "&quot;")
        else:
            data = "%s" % data
    else:
        data = '%s' % data
    return data
# EOF: def quoteattr

#############################################################################################
# FUNC     : encode_uri_double_percent_hex
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Encode a URI with Double Percent Hex Encoding. Ripped from wsfuzzer
#            i.e. 'A' => %2541
def encode_uri_double_percent_hex(str = ""):
    '''
    Encode a URI with Double Percent Hex Encoding. Ripped from wsfuzzer
    i.e. 'A' => %2541
    
    @type str: string
    @param str: String to be encoded.
    @return: Encoded string.
    '''
    strt = ""
    con = "%%%02x"
        
    # first get it in straight hex
    strt = encode_hex(str)        
    strt = strt.replace("%", con % ord("%"))

    return strt
# EOF: def encode_uri_double_percent_hex

#############################################################################################
# FUNC     : encode_uri_double_nibble_hex
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Encode a URI with Double Nibble Hex Encoding. Ripped from wsfuzzer.
#            i.e. 'A' => %%34%31
def encode_uri_double_nibble_hex(str = ""):
    '''
    Encode a URI with Double Nibble Hex Encoding. Ripped from wsfuzzer.
    i.e. 'A' => %%34%31
    
    @type str: string
    @param str: String to be encoded.
    @return: Encoded string.
    '''
    strt = ""
    fin = ""
    con = "%%%02x"
    p = re.compile(r"/|;|=|:|&|@|\\|\?")    

    # first get it in straight hex
    strt = encode_hex(str)
            
    for c in strt:
        if not c == "%":
            if p.search(c):
                fin += c
                continue
            fin += con % ord(c)
        else:
            fin += c
                
    return fin
# EOF: def encode_uri_double_nibble_hex

#############################################################################################
# FUNC     : encode_uri_first_nibble_hex
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Encode a URI with First Nibble Hex Encoding. Ripped from wsfuzzer.
#            i.e. 'A' => %%341
def encode_uri_first_nibble_hex(str = ""):
    '''
    Encode a URI with First Nibble Hex Encoding. Ripped from wsfuzzer.
    i.e. 'A' => %%341
    
    @type str: string
    @param str: String to be encoded.
    @return: Encoded string.    
    '''
    strt = ""
    fin = ""
    con = "%%%02x"
    p = re.compile(r"/|;|=|:|&|@|\\|\?")    

    # first get it in straight hex
    strt = encode_hex(str)
        
    count = 0
    for c in strt:
        if not c == "%":
            if p.search(c):
                fin += c
                continue
            if count == 1:
                fin += con % ord(c)
            if count == 2:
                fin += c
        else:
            fin += c
        count += 1
        # reset counter to 0 so as to handle the
        # hex pattern of %XX
        if count == 3:
            count = 0
                
    return fin
# EOF: def encode_uri_first_nibble_hex

#############################################################################################
# FUNC     : encode_uri_second_nibble_hex
# PARAMS   : string
# RETURN   : string
# ABSTRACT : Encode a URI with Second Nibble Hex Encoding. Ripped from wsfuzzer.
#            i.e. 'A' => %4%31   
def encode_uri_second_nibble_hex(str = ""):
    '''
    Encode a URI with Second Nibble Hex Encoding. Ripped from wsfuzzer.
    i.e. 'A' => %4%31   
    
    @type str: string
    @param str: String to be encoded.
    @return: Encoded string.
    '''
    strt = ""
    fin = ""
    con = "%%%02x"
    p = re.compile(r"/|;|=|:|&|@|\\|\?")    

    # first get it in straight hex
    strt = encode_hex(str)
        
    count = 0
    for c in strt:
        if not c == "%":
            if p.search(c):
                fin += c
                continue
            if count == 1:
                fin += c
            if count == 2:
                fin += con % ord(c)
        else:
            fin += c
        count += 1
        # reset counter to 0 so as to handle the 
        # hex pattern of %XX
        if count == 3:
            count = 0
                
    return fin
# EOF: def encode_uri_second_nibble_hex

# RL+I EOF
