source: server/lib/gutenbach/server/requests.py @ 9eeab06

no-cups
Last change on this file since 9eeab06 was 9eeab06, checked in by Jessica B. Hamrick <jhamrick@…>, 12 years ago

Using logging, not print statements; move skeleton handler functions into the correct class in server/requests.py

  • Property mode set to 100644
File size: 8.0 KB
Line 
1import BaseHTTPServer
2import gutenbach.ipp as ipp
3import gutenbach.ipp.constants as const
4from gutenbach.server.printer import GutenbachPrinter
5from gutenbach.server.exceptions import MalformedIPPRequestException
6import logging
7
8# initialize logger
9logger = logging.getLogger(__name__)
10
11def handler_for(operation):
12    """A decorator method to mark a function with the operation id
13    that it handles.  This value will be stored in
14    'func.ipp_operation'.
15
16    """
17   
18    def f(func):
19        func.ipp_operation = operation
20        return func
21    return f
22
23class GutenbachRequestHandler(object):
24
25    def __init__(self):
26        self.printers = {
27            "test": GutenbachPrinter(name="test")
28            }
29        self.default = "test"
30   
31    def handle(self, request, response):
32        # look up the handler
33        handler = None
34        handler_name = None
35        for d in dir(self):
36            if getattr(getattr(self, d), "ipp_operation", None) == request.operation_id:
37                handler_name = d
38                break
39        # we couldn't find a handler, so default to unknown operation
40        if handler_name is None:
41            handler_name = "unknown_operation"
42        # call the handler
43        handler = getattr(self, handler_name)
44        logger.debug("Sending request to handler '%s'" % handler_name)
45        handler(request, response)
46
47    def unknown_operation(self, request, response):
48        logger.warning("Received unknown operation 0x%x" % request.operation_id)
49        response.operation_id = const.StatusCodes.OPERATION_NOT_SUPPORTED
50
51    ##### Helper functions
52
53    def _get_printer_attributes(self, printer, request, response):
54        response.attribute_groups.append(ipp.AttributeGroup(
55            const.AttributeTags.PRINTER,
56            printer.get_printer_attributes(request)))
57
58    def _get_job_attributes(self, job_id, printer, request, response):
59        response.attribute_groups.append(ipp.AttributeGroup(
60            const.AttributeTags.JOB,
61            job.get_job_attributes(request)))
62
63    def _get_printer_name(self, request):
64        # make sure the first group is an OPERATION group
65        group_tag = request.attribute_groups[0].tag
66        if group_tag != const.AttributeTags.OPERATION:
67            raise MalformedIPPRequestException, \
68                  "Expected OPERATION group tag, got %d\n", group_tag
69
70        # make sure the printer-uri value is appropriate
71        printer_name_attr = request.attribute_groups[0]['printer-uri']
72        printer_name_value_tag = printer_name_attr.values[0].value_tag
73        if printer_name_value_tag != const.CharacterStringTags.URI:
74            raise MalformedIPPRequestException, \
75                  "Expected URI value tag, got %s" % printer_name_value_tag
76
77        # actually get the printer name
78        printer_name_value = printer_name_attr.values[0].value
79        # XXX: hack -- CUPS will strip the port from the request, so
80        # we can't do an exact comparison (also the hostname might be
81        # different, depending on the CNAME or whether it's localhost)
82        printer_name = printer_name_value.split("/")[-1]
83
84        # make sure the printer name is valid
85        if printer_name not in self.printers:
86            raise ValueError, "Invalid printer uri: %s" % printer_name_value
87
88        return printer_name
89
90    ##### Printer Commands
91
92    def print_job(self, request, response):
93        pass
94
95    def validate_job(self, request, response):
96        pass
97
98    @handler_for(const.Operations.GET_JOBS)
99    def get_jobs(self, request, response):
100        printer_name = self._get_printer_name(request)
101        # Each job will append a new job attribute group.
102        for job in self.printers[printer_name].get_jobs():
103            self._get_job_attributes(job, request, response)
104        response.operation_id = const.StatusCodes.OK
105
106    def print_uri(self, request, response):
107        pass
108
109    def create_job(self, request, response):
110        pass
111
112    def pause_printer(self, request, response):
113        pass
114
115    def resume_printer(self, request, response):
116        pass
117
118    @handler_for(const.Operations.GET_PRINTER_ATTRIBUTES)
119    def get_printer_attributes(self, request, response):
120        # this is just like cups_get_default, except the printer name
121        # is given
122        printer_name = self._get_printer_name(request)
123        self._get_printer_attributes(self.printers[printer_name], request, response)
124        response.operation_id = const.StatusCodes.OK
125
126    def set_printer_attributes(self, request, response):
127        pass
128
129    ##### Job Commands
130
131    def cancel_job(self, request, response):
132        pass
133
134    def send_document(self, request, response):
135        pass
136
137    def send_uri(self, request, response):
138        pass
139
140    def get_job_attributes(self, request, response):
141        printer_name = self._get_printer_name(request)
142        job_id = self._get_job_id(request)
143        self._get_job_attributes(
144            self.printers[printer_name].get_job(job_id), request, response)
145
146    def set_job_attributes(self, request, response):
147        pass
148
149    def cups_get_document(self, request, response):
150        pass
151
152    def restart_job(self, request, response):
153        pass
154
155    def promote_job(self, request, response):
156        pass
157
158
159    ##### CUPS Specific Commands
160
161    @handler_for(const.Operations.CUPS_GET_DEFAULT)
162    def cups_get_default(self, request, response):
163        self._get_printer_attributes(self.printers[self.default], request, response)
164        response.operation_id = const.StatusCodes.OK
165
166    @handler_for(const.Operations.CUPS_GET_PRINTERS)
167    def cups_get_printers(self, request, response):
168        # Each printer will append a new printer attribute group.
169        for printer in self.printers:
170            self._get_printer_attributes(self.printers[printer], request, response)
171        response.operation_id = const.StatusCodes.OK
172
173    @handler_for(const.Operations.CUPS_GET_CLASSES)
174    def cups_get_classes(self, request, response):
175        response.operation_id = const.StatusCodes.OK
176        # We have no printer classes, so nothing to return.
177
178class GutenbachIPPServer(BaseHTTPServer.BaseHTTPRequestHandler):
179    def setup(self):
180        self.root = GutenbachRequestHandler()
181        BaseHTTPServer.BaseHTTPRequestHandler.setup(self)
182
183    def handle_one_request(self):
184        self.raw_requestline = self.rfile.readline()
185        if not self.raw_requestline:
186            self.close_connection = 1
187            return
188        if not self.parse_request(): # An error code has been sent, just exit
189            return
190        self.handle_ipp()
191
192    def handle_ipp(self):
193        # Receive a request
194        length = int(self.headers.getheader('content-length', 0))
195        request = ipp.Request(request=self.rfile, length=length)
196        logger.debug("Received request: %s" % repr(request))
197
198        # Attributes
199        attributes = [
200            ipp.Attribute(
201                'attributes-charset',
202                [ipp.Value(ipp.Tags.CHARSET, 'utf-8')]),
203            ipp.Attribute(
204                'attributes-natural-language',
205                [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, 'en-us')])
206            ]
207        # Attribute group
208        attribute_group = ipp.AttributeGroup(
209            const.AttributeTags.OPERATION,
210            attributes)
211
212        # Set up the response
213        response_kwargs = {}
214        response_kwargs['version']          = request.version
215        response_kwargs['operation_id']     = const.StatusCodes.INTERNAL_ERROR
216        response_kwargs['request_id']       = request.request_id
217        response_kwargs['attribute_groups'] = [attribute_group]
218        response = ipp.Request(**response_kwargs)
219
220        # Get the handler and pass it the request and response objects
221        self.root.handle(request, response)
222        logger.debug("Sending response: %s" % repr(response))
223
224        # Send the response across HTTP
225        self.send_response(200, "o hai")
226        self.send_header("Content-Type", "application/ipp")
227        self.send_header("Connection", "close")
228        self.end_headers()
229        self.wfile.write(response.packed_value)
Note: See TracBrowser for help on using the repository browser.