Changeset 8403f61


Ignore:
Timestamp:
Nov 6, 2010, 6:59:32 PM (13 years ago)
Author:
Jessica B. Hamrick <jhamrick@…>
Branches:
no-cups
Children:
478ca74
Parents:
d56a0bc
git-author:
Jessica B. Hamrick <jhamrick@…> (11/06/10 18:59:32)
git-committer:
Jessica B. Hamrick <jhamrick@…> (11/06/10 18:59:32)
Message:

Fix ipprequest (had misimplemented the spec)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • server/lib/ipprequest.py

    rd56a0bc r8403f61  
    11#!/usr/bin/python
    22
    3 import sys, struct
     3import sys, struct, logging
     4
     5# initialize logger
     6logger = logging.getLogger("ippLogger")
    47
    58class IPPTags():
     
    3336    DATETIME                          = 0x31
    3437    RESOLUTION                        = 0x32
    35     RANGEOFINTEGER                    = 0x33
     38    RANGE_OF_INTEGER                  = 0x33
    3639    COLLECTION                        = 0x34
    37     TEXTWITHLANGUAGE                  = 0x35
    38     NAMEWITHLANGUAGE                  = 0x36
     40    TEXT_WITH_LANGUAGE                = 0x35
     41    NAME_WITH_LANGUAGE                = 0x36
    3942
    4043    # character-string value tags
    4144    GENERIC_CHAR_STRING               = 0x40
    42     TEXTWITHOUTLANGUAGE               = 0x41
    43     NAMEWITHOUTLANGUAGE               = 0x42
     45    TEXT_WITHOUT_LANGUAGE             = 0x41
     46    NAME_WITHOUT_LANGUAGE             = 0x42
    4447    KEYWORD                           = 0x44
    4548    URI                               = 0x45
    46     URISCHEME                         = 0x46
     49    URI_SCHEME                        = 0x46
    4750    CHARSET                           = 0x47
    48     NATURALLANGUAGE                   = 0x48
    49     MIMEMEDIATYPE                     = 0x49                                   
     51    NATURAL_LANGUAGE                  = 0x48
     52    MIME_MEDIA_TYPE                   = 0x49                                   
    5053
    5154class IPPValue():
     
    6770    """
    6871
    69     def __init__(self, value_tag, name, value):
     72    def __init__(self, value_tag, value):
    7073        """
    7174        Initialize an IPPValue:
     
    7477
    7578            value_tag -- one byte, identifying the type of value
    76 
    77             name -- (optional) variable size, identifying the name of
    78                     this value
    7979
    8080            value -- variable size, containing the actual value
     
    8383        # make sure value_tag isn't empty
    8484        assert value_tag is not None
    85         # make sure the size of value_tag is one byte
    86         assert sys.getsizeof(value_tag) == 1
    8785        # make sure value isn't empty
    8886        assert value is not None
    8987
    9088        self.value_tag = hex(value_tag)
     89        self.value = str(value)
     90
     91class IPPAttribute():
     92    """
     93    In addition to what the RFC reports, an attribute has an
     94    'attribute tag', which specifies what type of attribute it is.
     95    It is 1 bytes long, and comes before the list of values.
     96
     97    From RFC 2565:
     98
     99    Each attribute consists of:
     100    -----------------------------------------------
     101    |                   value-tag                 |   1 byte
     102    -----------------------------------------------
     103    |               name-length  (value is u)     |   2 bytes
     104    -----------------------------------------------
     105    |                     name                    |   u bytes
     106    -----------------------------------------------
     107    |              value-length  (value is v)     |   2 bytes
     108    -----------------------------------------------
     109    |                     value                   |   v bytes
     110    -----------------------------------------------
     111
     112    An additional value consists of:
     113    -----------------------------------------------------------
     114    |                   value-tag                 |   1 byte  |
     115    -----------------------------------------------           |
     116    |            name-length  (value is 0x0000)   |   2 bytes |
     117    -----------------------------------------------           |-0 or more
     118    |              value-length (value is w)      |   2 bytes |
     119    -----------------------------------------------           |
     120    |                     value                   |   w bytes |
     121    -----------------------------------------------------------
     122    """
     123
     124    def __init__(self, name, values):
     125        """
     126        Initialize an IPPAttribute.
     127       
     128        Arguments:
     129
     130        name -- the name of the attribute
     131
     132        values -- a list of IPPValues.  May not be empty.
     133        """
     134
     135        # make sure name isn't empty
     136        assert name is not None
     137         
     138        # make sure the list of values isn't empty
     139        assert len(values) > 0
     140        # make sure each value is an IPPValue
     141        for value in values: assert isinstance(value, IPPValue)
     142         
    91143        self.name = str(name)
    92         self.value = str(value)
     144        self.values = values
    93145
    94146    def toBinaryData(self):
    95147        """
    96         Packs the value data into binary data.
    97         """
    98        
    99         # get the length in bytes of the name
    100         name_length = sys.getsizeof(name)
    101         # get the length in bytes of the value
    102         value_length = sys.getsizeof(value)
    103 
    104         # if the name is of length zero, then don't include it in the
    105         # binary data
    106         if name_length == IPPTags.ZERO_NAME_LENGTH:
    107             binary = struct.pack('>bhhs',
    108                                  self.value_tag,
    109                                  name_length,
    110                                  value_length,
    111                                  self.value)
    112         else:
    113             binary = struct.pack('>bhshs',
    114                                  self.value_tag,
    115                                  name_length,
    116                                  self.name,
    117                                  value_length,
    118                                  self.value)
    119 
    120         return binary
    121 
    122 class IPPAttribute():
    123      """
    124      In addition to what the RFC reports, an attribute has an
    125      'attribute tag', which specifies what type of attribute it is.
    126      It is 1 bytes long, and comes before the list of values.
    127 
    128      From RFC 2565:
    129 
    130      Each attribute consists of:
    131      -----------------------------------------------
    132      |                   value-tag                 |   1 byte
    133      -----------------------------------------------
    134      |               name-length  (value is u)     |   2 bytes
    135      -----------------------------------------------
    136      |                     name                    |   u bytes
    137      -----------------------------------------------
    138      |              value-length  (value is v)     |   2 bytes
    139      -----------------------------------------------
    140      |                     value                   |   v bytes
    141      -----------------------------------------------
    142 
    143      An additional value consists of:
    144      -----------------------------------------------------------
    145      |                   value-tag                 |   1 byte  |
    146      -----------------------------------------------           |
    147      |            name-length  (value is 0x0000)   |   2 bytes |
    148      -----------------------------------------------           |-0 or more
    149      |              value-length (value is w)      |   2 bytes |
    150      -----------------------------------------------           |
    151      |                     value                   |   w bytes |
    152      -----------------------------------------------------------
    153      """
    154 
    155      def __init__(self, attribute_tag, values):
    156          """
    157          Initialize an IPPAttribute.
    158 
    159          Arguments:
    160 
    161              attribute_tag -- one byte, identifying the type of attribute
    162 
    163              values -- a list of IPPValues.  May not be empty.
    164          """
    165 
    166          # make sure attribute_tag isn't empty
    167          assert attribute_tag is not None
    168          # make sure attribute_tag is of the right size
    169          assert sys.getsizeof(attribute_tag) == 1
    170          
    171          # make sure the list of values isn't empty
    172          assert len(values) > 0
    173          # make sure each value is an IPPValue
    174          for value in values: assert isinstance(value, IPPValue)
    175        
    176          self.attribute_tag = hex(attribute_tag)
    177          self.values = values
    178 
    179     def toBinaryData(self):
    180         """
    181148        Packs the attribute data into binary data.
    182149        """
    183150
    184         # pack the attribute tag
    185         attribute_tag = struct.pack('>b', self.attribute_tag)
    186151        # get the binary data for all the values
    187         values = [v.toBinaryData() for v in self.values]
    188 
     152        values = []
     153        for v, i in zip(self.values, xrange(len(self.values))):
     154            if i == 0:
     155                name_length = sys.getsizeof(self.name)
     156                value_length = sys.getsizeof(v.value)
     157                values.append(struct.pack('>bh%ssh%ss' % (name_length, value_length),
     158                                          v.value_tag,
     159                                          name_length,
     160                                          self.name,
     161                                          value_length,
     162                                          v.value))
     163            else:
     164                value_length = sys.getsizeof(v.value)
     165                values.append(struct.pack('>bhh%ss' % (value_length),
     166                                          v.value_tag,
     167                                          name_length,
     168                                          value_length,
     169                                          v.value))
     170               
    189171        # concatenate everything together and return it
    190         return attribute_tag + ''.join(values)
     172        return ''.join(values)
    191173
    192174class IPPRequest():
     
    253235            assert isinstance(version, tuple)
    254236            assert len(version) == 2
    255             # make sure the major version number is one byte long
    256             assert sys.getsizeof(version[0]) == 1
    257             # make sure the minor version number is one byte long
    258             assert sys.getsizeof(version[1]) == 1
    259237            # make sure the operation id isn't empty
    260238            assert operation_id is not None
    261             # make sure the operation id is two bytes long
    262             assert sys.getsizeof(operation_id) == 2
    263239            # make sure the request id isn't empty
    264240            assert request_id is not None
    265             # make sure the request id is four bytes long
    266             assert sys.getsizeof(request_id) == 4
    267241           
    268242        # if the request isn't None, then we'll read directly from
     
    271245            # read the version-number (two signed chars)
    272246            self.version        = struct.unpack('>bb', request.read(2))
     247            logger.debug("version-number : (0x%X, 0x%X)" % self.version)
    273248
    274249            # read the operation-id (or status-code, but that's only
    275250            # for a response) (signed short)
    276             self.operation_id   = struct.unpack('>h', request.read(2))
     251            self.operation_id   = struct.unpack('>h', request.read(2))[0]
     252            logger.debug("operation-id : 0x%X" % self.operation_id)
    277253
    278254            # read the request-id (signed int)
    279             self.request_id     = struct.unpack('>i', request.read(4))
     255            self.request_id     = struct.unpack('>i', request.read(4))[0]
     256            logger.debug("request-id : 0x%X" % self.request_id)
    280257
    281258            # now we have to read in the attributes.  Each attribute
     
    284261
    285262            # read in the next byte
    286             next_byte = struct.unpack('>b', request.read(1))
     263            next_byte = struct.unpack('>b', request.read(1))[0]
     264            logger.debug("next byte : 0x%X" % next_byte)
    287265
    288266            # as long as the next byte isn't signaling the end of the
     
    290268            while next_byte != IPPTags.END_OF_ATTRIBUTES_TAG:
    291269               
    292                 # if the next byte is an attribute tag, then we're at
    293                 # the start of a new attribute
    294                 if next_byte <= 0x0F:
    295 
    296                     attribute_tag = next_byte
     270                attribute_group_tag = next_byte
     271                logger.debug("attribute-tag : %i" % attribute_group_tag)
     272
     273                next_byte = struct.unpack('>b', request.read(1))[0]
     274                logger.debug("next byte : 0x%X" % next_byte)
     275
     276                while next_byte > 0x0F:
     277                   
    297278                    # read in the value tag (signed char)
    298                     value_tag     = struct.unpack('>b', request.read(1))
     279                    value_tag     = next_byte
     280                    logger.debug("value-tag : 0x%X" % value_tag)
     281                   
    299282                    # read in the length of the name (signed short)
    300                     name_length   = struct.unpack('>h', request.read(2))
    301                     # read the name (a string of name_length bytes)
    302                     name          = struct.unpack('>s', request.read(name_length))
    303                     # read in the length of the value (signed short)
    304                     value_length  = struct.unpack('>h', request.read(2))
    305                     # read in the value (string of value_length bytes)
    306                     value         = struct.unpack('>%sb' % value_length, request.read(value_length))
    307 
    308                     # create a new IPPAttribute from the data we just
    309                     # read in, and add it to our attributes list
    310                     self.attributes.append(IPPAttribute(
    311                         attribute_tag,
    312                         [IPPValue(value_tag, name, value)]))
    313 
    314                 # otherwise, we're still in the process of reading the
    315                 # current attribute (now we'll read in another value)
    316                 else:
    317                    
    318                     value_tag     = next_byte
    319                     # read in the length of the name (two bytes) --
    320                     # this should be 0x0
    321                     name_length   = struct.unpack('>h', request.read(2))
    322                     assert name_length == IPPTags.ZERO_NAME_LENGTH
    323                     # name should be empty
    324                     name          = ''
    325                     # read in the length of the value (two bytes)
    326                     value_length  = struct.unpack('>h', request.read(2))
    327                     # read in the value (value_length bytes)
    328                     value         = struct.unpack('>%sb' % value_length, request.read(value_length))
    329 
    330                     # add another value to the last attribute
    331                     self.attributes[-1].values.append(IPPValue(value_tag, name, value))
    332 
    333                 # read another byte
    334                 next_byte = struct.unpack('>b', request.read(1))
     283                    name_length   = struct.unpack('>h', request.read(2))[0]
     284                    logger.debug("name-length : %i" % name_length)
     285                   
     286                    if name_length != IPPTags.ZERO_NAME_LENGTH:
     287                        # read the name (a string of name_length bytes)
     288                        name          = request.read(name_length)
     289                        logger.debug("name : %s" % name)
     290                   
     291                        # read in the length of the value (signed short)
     292                        value_length  = struct.unpack('>h', request.read(2))[0]
     293                        logger.debug("value-length : %i" % value_length)
     294                   
     295                        # read in the value (string of value_length bytes)
     296                        value         = request.read(value_length)
     297                        logger.debug("value : %s" % value)
     298
     299                        # create a new IPPAttribute from the data we just
     300                        # read in, and add it to our attributes list
     301                        self.attributes.append(IPPAttribute(name,
     302                                                            [IPPValue(value_tag, value)]))
     303
     304                    else:
     305                        # read in the length of the value (signed short)
     306                        value_length  = struct.unpack('>h', request.read(2))[0]
     307                        logger.debug("value-length : %i" % value_length)
     308                   
     309                        # read in the value (string of value_length bytes)
     310                        value         = request.read(value_length)
     311                        logger.debug("value : %s" % value)
     312
     313                        # add another value to the last attribute
     314                        self.attributes[-1].values.append(IPPValue(value_tag, value))
     315
     316                    # read another byte
     317                    next_byte = struct.unpack('>b', request.read(1))[0]
    335318
    336319            # once we hit the end-of-attributes tag, the only thing
    337320            # left is the data, so go ahead and read all of it
    338             buff = request.read()
    339             self.data = struct.unpack('>%sb' % len(buff), sys.getsizeof(buff))
     321            self.data = request.read()
     322            logger.debug("data : %s" % self.data)
    340323
    341324        # otherwise, just set the class variables to the keyword
    342325        # arguments passed in
    343326        else:
    344             self.version = int(version)
     327            self.version = (int(version[0]), int(version[1]))
    345328            self.operation_id = int(operation_id)
    346329            self.request_id = int(request_id)
     
    361344
    362345        # convert the attributes to binary
    363         attributes = ''.join([a.toBinaryData() for a in attributes])
     346        attributes = ''.join([a.toBinaryData() for a in self.attributes])
    364347
    365348        # conver the end-of-attributes-tag to binary
     
    367350
    368351        # convert the data to binary
    369         data = ''.join([struct.pack('>b', x) for x in self.data])
     352        if self.data is not None:
     353            data = ''.join([struct.pack('>b', x) for x in self.data])
     354        else:
     355            data = ''
    370356
    371357        # append everything together and return it
Note: See TracChangeset for help on using the changeset viewer.