~ubuntu-branches/ubuntu/raring/hplip/raring

« back to all changes in this revision

Viewing changes to scan/sane/http.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2010-12-23 11:04:31 UTC
  • mfrom: (2.1.158 natty)
  • Revision ID: james.westby@ubuntu.com-20101223110431-ev5wz1it6b7jce51
Tags: 3.10.9-1
New Upstream Release 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************************************************\
 
2
  http.c - HTTP/1.1 feeder and consumer
 
3
 
 
4
  (c) 2008 Copyright Hewlett-Packard Development Company, LP
 
5
 
 
6
  Permission is hereby granted, free of charge, to any person obtaining a copy 
 
7
  of this software and associated documentation files (the "Software"), to deal 
 
8
  in the Software without restriction, including without limitation the rights 
 
9
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 
10
  of the Software, and to permit persons to whom the Software is furnished to do 
 
11
  so, subject to the following conditions:
 
12
 
 
13
  The above copyright notice and this permission notice shall be included in all
 
14
  copies or substantial portions of the Software.
 
15
 
 
16
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 
17
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
 
18
  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 
19
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
 
20
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 
21
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
  In order to support state-less connections, each HTTP/1.1 connection or session 
 
24
  must start with http_open and end with http_close. 
 
25
 
 
26
  Author: Naga Samrat Chowdary, Narla
 
27
\************************************************************************************/
 
28
 
 
29
#ifndef _GNU_SOURCE
 
30
#define _GNU_SOURCE
 
31
#endif
 
32
 
 
33
#include <stdio.h>
 
34
#include <stdlib.h>
 
35
#include <string.h>
 
36
#include <syslog.h>
 
37
#include <ctype.h>
 
38
#include "hpmud.h"
 
39
#include "http.h"
 
40
 
 
41
//#define HTTP_DEBUG
 
42
 
 
43
#define _STRINGIZE(x) #x
 
44
#define STRINGIZE(x) _STRINGIZE(x)
 
45
 
 
46
#define BUG(args...) syslog(LOG_ERR, __FILE__ " " STRINGIZE(__LINE__) ": " args)
 
47
 
 
48
#ifdef HTTP_DEBUG
 
49
   #define DBG(args...) syslog(LOG_INFO, __FILE__ " " STRINGIZE(__LINE__) ": " args)
 
50
   #define DBG_DUMP(data, size) sysdump((data), (size))
 
51
   #define DBG_SZ(args...) syslog(LOG_INFO, args)
 
52
#else
 
53
   #define DBG(args...)
 
54
   #define DBG_DUMP(data, size)
 
55
   #define DBG_SZ(args...)
 
56
#endif
 
57
 
 
58
#define EXCEPTION_TIMEOUT 45 /* seconds */
 
59
 
 
60
enum HTTP_STATE
 
61
{
 
62
   HS_ACTIVE = 1,
 
63
   HS_EOF,
 
64
};
 
65
 
 
66
struct stream_buffer
 
67
{
 
68
   char buf[4096];
 
69
   int index;
 
70
   int cnt;   
 
71
};
 
72
 
 
73
struct http_session
 
74
{
 
75
   enum HTTP_STATE state;
 
76
   int http_status;
 
77
   int footer;         /* current footer */
 
78
   int total;
 
79
   HPMUD_DEVICE dd;  /* hpiod device descriptor */
 
80
   HPMUD_CHANNEL cd;  /* hpiod soap channel descriptor */
 
81
   struct stream_buffer s;
 
82
};
 
83
 
 
84
#if 0
 
85
static char *strnstr(const char *haystack, const char *needle, size_t n)
 
86
{
 
87
   int i, len=strlen(needle);
 
88
 
 
89
   for (i=0; *haystack && i<n; ++haystack, i++)
 
90
   {
 
91
      if (strncmp(haystack, needle, len) == 0)
 
92
      {
 
93
         return ((char *)haystack);
 
94
      }
 
95
   }
 
96
   return 0;
 
97
}
 
98
#endif
 
99
 
 
100
#if 0
 
101
static void sysdump(const void *data, int size)
 
102
{
 
103
    /* Dump size bytes of *data. Output looks like:
 
104
     * [0000] 75 6E 6B 6E 6F 77 6E 20 30 FF 00 00 00 00 39 00 unknown 0.....9.
 
105
     */
 
106
 
 
107
    unsigned char *p = (unsigned char *)data;
 
108
    unsigned char c;
 
109
    int n;
 
110
    char bytestr[4] = {0};
 
111
    char addrstr[10] = {0};
 
112
    char hexstr[16*3 + 5] = {0};
 
113
    char charstr[16*1 + 5] = {0};
 
114
    for(n=1;n<=size;n++) {
 
115
        if (n%16 == 1) {
 
116
            /* store address for this line */
 
117
            snprintf(addrstr, sizeof(addrstr), "%.4d", (int)((p-(unsigned char *)data) & 0xffff));
 
118
        }
 
119
            
 
120
        c = *p;
 
121
        if (isprint(c) == 0) {
 
122
            c = '.';
 
123
        }
 
124
 
 
125
        /* store hex str (for left side) */
 
126
        snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
 
127
        strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
 
128
 
 
129
        /* store char str (for right side) */
 
130
        snprintf(bytestr, sizeof(bytestr), "%c", c);
 
131
        strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
 
132
 
 
133
        if(n%16 == 0) { 
 
134
            /* line completed */
 
135
            DBG_SZ("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
 
136
            hexstr[0] = 0;
 
137
            charstr[0] = 0;
 
138
        }
 
139
        p++; /* next byte */
 
140
    }
 
141
 
 
142
    if (strlen(hexstr) > 0) {
 
143
        /* print rest of buffer if not empty */
 
144
        DBG_SZ("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
 
145
    }
 
146
}
 
147
#endif
 
148
 
 
149
/* Read data into stream buffer. Return specified "size" or less. Unused data is left in the stream. */
 
150
static int read_stream(struct http_session *ps, char *data, int size, int sec_timeout, int *bytes_read)
 
151
{
 
152
   int len, stat=1;
 
153
   int tmo=sec_timeout;        /* initial timeout */
 
154
   int max=sizeof(ps->s.buf);
 
155
   enum HPMUD_RESULT ret;
 
156
 
 
157
   DBG("read_stream() ps=%p data=%p size=%d timeout=%d s.index=%d s.cnt=%d\n", ps, data, size, sec_timeout, ps->s.index, ps->s.cnt);
 
158
 
 
159
   *bytes_read = 0;
 
160
 
 
161
   /* Return any data in the stream first. */
 
162
   if (ps->s.cnt)
 
163
   {
 
164
      if (ps->s.cnt > size)
 
165
      {
 
166
         /* Return part of stream buffer. */
 
167
         len = size;
 
168
         memcpy(data, &ps->s.buf[ps->s.index], len);
 
169
         ps->s.index += len;
 
170
         ps->s.cnt -= len;
 
171
      }
 
172
      else
 
173
      {
 
174
         /* Return all of rbuf. */
 
175
         len = ps->s.cnt;
 
176
         memcpy(data, &ps->s.buf[ps->s.index], len);
 
177
         ps->s.index = ps->s.cnt = 0;       /* stream is empty reset */
 
178
      }
 
179
      *bytes_read = len;
 
180
      DBG("-read_stream() bytes_read=%d s.index=%d s.cnt=%d\n", len, ps->s.index, ps->s.cnt);
 
181
      return 0;
 
182
   }
 
183
 
 
184
   /* Stream is empty read more data from device. */
 
185
   ret = hpmud_read_channel(ps->dd, ps->cd, &ps->s.buf[ps->s.index], max-(ps->s.index + ps->s.cnt), tmo, &len);
 
186
   if (ret == HPMUD_R_IO_TIMEOUT)
 
187
   {
 
188
      BUG("timeout reading data sec_timeout=%d\n", tmo);
 
189
      goto bugout;
 
190
   }
 
191
   if (ret != HPMUD_R_OK)
 
192
   {
 
193
      BUG("read_stream error stat=%d\n", ret);
 
194
      goto bugout;
 
195
   }
 
196
   if (len==0)
 
197
   {
 
198
      BUG("read_stream error len=0\n");   /* shouldn't happen, but it does with jetdirect */
 
199
      goto bugout;
 
200
   }
 
201
 
 
202
   DBG("read_channel len=%d\n", len);
 
203
   ps->s.cnt += len;
 
204
 
 
205
   if (ps->s.cnt > size)
 
206
   {
 
207
      /* Return part of stream buffer. */
 
208
      len = size;
 
209
      memcpy(data, &ps->s.buf[ps->s.index], len);
 
210
      ps->s.index += len;
 
211
      ps->s.cnt -= len;
 
212
   }
 
213
   else
 
214
   {
 
215
      /* Return all of rbuf. */
 
216
      len = ps->s.cnt;
 
217
      memcpy(data, &ps->s.buf[ps->s.index], len);
 
218
      ps->s.index = ps->s.cnt = 0;       /* stream is empty reset */
 
219
   }
 
220
 
 
221
   *bytes_read = len;
 
222
   stat = 0;
 
223
   DBG("-read_stream() bytes_read=%d s.index=%d s.cnt=%d\n", len, ps->s.index, ps->s.cnt);
 
224
 
 
225
bugout:
 
226
   return stat;
 
227
}
 
228
 
 
229
static int read_char(struct http_session *ps, int sec_timeout)
 
230
{
 
231
   unsigned char ch;
 
232
   int len;
 
233
   if (read_stream(ps, (char *)&ch, 1, sec_timeout, &len))
 
234
      return -1;
 
235
   else
 
236
      return ch;  
 
237
}
 
238
 
 
239
/* Read a line of data. Line length is not known. */
 
240
static int read_line(struct http_session *ps, char *line, int line_size, int sec_timeout, int *bytes_read)
 
241
{
 
242
   int total=0, stat=1;
 
243
   int ch, cr=0, lf=0;
 
244
   int tmo=sec_timeout;        /* initial timeout */
 
245
 
 
246
   *bytes_read = 0;
 
247
 
 
248
   while (total < (line_size-1))
 
249
   {
 
250
      ch = read_char(ps, tmo);
 
251
      line[total++]=ch;
 
252
 
 
253
      if (ch == '\r')
 
254
         cr=1;
 
255
      else if (ch == '\n' && cr)
 
256
         break;   /* done, found CRLF */
 
257
      else if (ch == '\n' && lf)
 
258
         break;   /* done, found LFLF (for kiwi "501 Not Implemented") */
 
259
      else if (ch == '\n')
 
260
         lf=1;
 
261
      else if (ch == -1)
 
262
         goto bugout;  /* error */
 
263
      else
 
264
      {
 
265
        cr=0;
 
266
        lf=0;
 
267
      }
 
268
      tmo=3;  /* changed 1 to 3 for 1200dpi uncompressed, DES 8/20/08. */ 
 
269
   }
 
270
   stat = 0;
 
271
 
 
272
bugout:
 
273
   line[total]=0;
 
274
   *bytes_read=total;   /* length does not include null termination */
 
275
   DBG("read_line len=%d index=%d cnt=%d\n", total, ps->s.index, ps->s.cnt);
 
276
   return stat;
 
277
}
 
278
 
 
279
/* Http_open must be called for each HTTP/1.1 connection or session. */
 
280
enum HTTP_RESULT __attribute__ ((visibility ("hidden"))) http_open(HPMUD_DEVICE dd, const char *channel, HTTP_HANDLE *handle)
 
281
{
 
282
   struct http_session *ps;
 
283
   enum HTTP_RESULT stat = HTTP_R_IO_ERROR;
 
284
   
 
285
   DBG("http_open() dd=%d channel=%s handle=%p\n", dd, channel, handle);
 
286
 
 
287
   *handle = NULL;
 
288
 
 
289
   if ((ps = malloc(sizeof(struct http_session))) == NULL)
 
290
   {
 
291
      BUG("malloc failed: %m\n");
 
292
      return HTTP_R_MALLOC_ERROR;
 
293
   }
 
294
   memset(ps, 0, sizeof(struct http_session));
 
295
 
 
296
   ps->dd = dd;
 
297
   if (hpmud_open_channel(ps->dd, channel, &ps->cd) != HPMUD_R_OK)
 
298
   {
 
299
      BUG("unable to open %s channel\n", channel);
 
300
      goto bugout;
 
301
   }
 
302
 
 
303
   ps->state = HS_ACTIVE;
 
304
   *handle = ps;
 
305
   stat = HTTP_R_OK;
 
306
 
 
307
bugout:
 
308
   if (stat != HTTP_R_OK)
 
309
      free(ps);
 
310
   return stat;
 
311
}
 
312
 
 
313
/* Http_close must be called after the HTTP/1.1 connection closes. */
 
314
enum HTTP_RESULT __attribute__ ((visibility ("hidden"))) http_close(HTTP_HANDLE handle)
 
315
{
 
316
   struct http_session *ps = (struct http_session *)handle;
 
317
   DBG("http_close() handle=%p\n", handle);
 
318
   if (ps->cd > 0)
 
319
      hpmud_close_channel(ps->dd, ps->cd);
 
320
   free(ps);
 
321
   return HTTP_R_OK;
 
322
}
 
323
 
 
324
/* Read HTTP/1.1 header. Blocks until header is read or timeout. */
 
325
enum HTTP_RESULT __attribute__ ((visibility ("hidden"))) http_read_header(HTTP_HANDLE handle, void *data, int max_size, int sec_timeout, int *bytes_read)
 
326
{
 
327
   struct http_session *ps = (struct http_session *)handle;
 
328
   int len, total; 
 
329
   int tmo=sec_timeout;   /* set initial timeout */
 
330
   enum HTTP_RESULT stat = HTTP_R_IO_ERROR;
 
331
 
 
332
   DBG("http_read_header() handle=%p data=%p size=%d sectime=%d\n", handle, data, max_size, sec_timeout);
 
333
 
 
334
   *bytes_read = 0;
 
335
 
 
336
   /* Read initial HTTP/1.1 header status line. */
 
337
   if (read_line(ps, data, max_size, tmo, &len))
 
338
      goto bugout;
 
339
   ps->http_status = strtol(data+9, NULL, 10);
 
340
 
 
341
   /* Check for good status, ignore 400 (no job id found for JobCancelRequest) */                    
 
342
   if (!((ps->http_status >= 200 && ps->http_status < 300) || ps->http_status == 400))
 
343
   {
 
344
      BUG("invalid http_status=%d\n", ps->http_status);
 
345
 
 
346
      /* Dump any outstanding payload here. */
 
347
      while (!read_stream(ps, data, max_size, 1, &len))
 
348
         BUG("dumping len=%d\n", len);
 
349
      goto bugout;                
 
350
   }
 
351
 
 
352
   /* Read rest of header. Look for blank line. */
 
353
   total = len;
 
354
   while (len > 2)
 
355
   {
 
356
      if (read_line(ps, data+total, max_size-total, tmo, &len))
 
357
         goto bugout;
 
358
      total += len;
 
359
   }
 
360
 
 
361
   stat = HTTP_R_OK;
 
362
 
 
363
   DBG("-http_read_header() handle=%p data=%p bytes_read=%d size=%d status=%d\n", handle, data, *bytes_read, max_size, stat);
 
364
 
 
365
bugout:
 
366
   return stat;
 
367
};
 
368
 
 
369
/* Reads data from HTTP/1.1 chunked data stream until EOF. Returns max_size or less. */
 
370
enum HTTP_RESULT __attribute__ ((visibility ("hidden"))) http_read_payload(HTTP_HANDLE handle, void *data, int max_size, int sec_timeout, int *bytes_read)
 
371
{
 
372
   struct http_session *ps = (struct http_session *)handle;
 
373
   char line[128];
 
374
   int len; 
 
375
   int tmo=sec_timeout;   /* set initial timeout */
 
376
   enum HTTP_RESULT stat = HTTP_R_IO_ERROR;
 
377
 
 
378
   DBG("http_read_payload() handle=%p data=%p size=%d sectime=%d\n", handle, data, max_size, sec_timeout);
 
379
 
 
380
   *bytes_read = 0;
 
381
 
 
382
   if (ps->state == HS_EOF)
 
383
   {
 
384
      stat = HTTP_R_EOF;
 
385
   }
 
386
   else
 
387
   {
 
388
      if (ps->footer)
 
389
      {
 
390
         /* Footer is not complete. Continue reading payload. */
 
391
         if (read_stream(ps, data, ps->footer < max_size ? ps->footer : max_size, tmo, &len))
 
392
            goto bugout;
 
393
 
 
394
         ps->total += len;
 
395
         ps->footer -= len;
 
396
         *bytes_read = len;
 
397
 
 
398
         if (ps->footer == 0)
 
399
            if (read_line(ps, line, sizeof(line), tmo, &len))   /* footer is complete, eat CRLF */
 
400
               goto bugout;
 
401
 
 
402
         stat = HTTP_R_OK;
 
403
      }
 
404
      else
 
405
      {
 
406
         /* Read new footer. */
 
407
         if (read_line(ps, line, sizeof(line), tmo, &len))
 
408
            goto bugout;
 
409
         ps->footer = strtol(line, NULL, 16);
 
410
 
 
411
         /* Check for zero footer. */
 
412
         if (ps->footer == 0)
 
413
         {
 
414
            /* Done eat blank line. */
 
415
            read_line(ps, line, sizeof(line), 1, &len);
 
416
            ps->state = HS_EOF;
 
417
            stat = HTTP_R_EOF;
 
418
         }
 
419
         else
 
420
         {
 
421
            /* Got a valid footer, continue reading payload. */
 
422
            if (read_stream(ps, data, ps->footer < max_size ? ps->footer : max_size, tmo, &len))
 
423
               goto bugout;
 
424
 
 
425
            ps->total += len;
 
426
            ps->footer -= len;
 
427
            *bytes_read = len;
 
428
 
 
429
            if (ps->footer == 0)
 
430
               if (read_line(ps, line, sizeof(line), tmo, &len))   /* footer is complete, eat CRLF */
 
431
                  goto bugout;
 
432
 
 
433
            stat = HTTP_R_OK;
 
434
         }
 
435
      }
 
436
   }  /* if (ps->state == HS_EOF) */
 
437
 
 
438
   DBG("-http_read_payload() handle=%p data=%p bytes_read=%d size=%d status=%d\n", handle, data, *bytes_read, max_size, stat);
 
439
 
 
440
bugout:
 
441
   return stat;
 
442
};
 
443
 
 
444
/* Reads data from HTTP/1.1 chunked data stream until EOF. Returns max_size or less. */
 
445
enum HTTP_RESULT __attribute__ ((visibility ("hidden"))) http_read(HTTP_HANDLE handle, void *data, int max_size, int sec_timeout, int *bytes_read)
 
446
{
 
447
   struct http_session *ps = (struct http_session *)handle;
 
448
   char line[128];
 
449
   int len;
 
450
   int tmo=sec_timeout;   /* set initial timeout */
 
451
   enum HTTP_RESULT stat = HTTP_R_IO_ERROR;
 
452
   int total_payload_length=*bytes_read;
 
453
 
 
454
   DBG("http_read() handle=%p data=%p size=%d sectime=%d\n", handle, data, max_size, sec_timeout);
 
455
 
 
456
   ps->footer=total_payload_length;
 
457
 
 
458
   *bytes_read = 0;
 
459
 
 
460
         /* Read new footer. */
 
461
         while(ps->footer)
 
462
         {
 
463
          if (read_line(ps, line, sizeof(line), tmo, &len)){
 
464
         *bytes_read = (ps->footer) * (-1) + 12;
 
465
            goto bugout; }
 
466
         strcpy(data, line);
 
467
         data=data+len;
 
468
         ps->footer -= len;
 
469
 
 
470
         }      
 
471
 
 
472
            stat = HTTP_R_OK;
 
473
            if(ps->footer == 0) stat=HTTP_R_EOF;
 
474
 
 
475
   DBG("-http_read() handle=%p data=%p bytes_read=%d size=%d status=%d\n", handle, data, *bytes_read, max_size, stat);
 
476
 
 
477
bugout:
 
478
   return stat;
 
479
};
 
480
 
 
481
enum HTTP_RESULT __attribute__ ((visibility ("hidden"))) http_read_size(HTTP_HANDLE handle, void *data, int max_size, int sec_timeout, int *bytes_read)
 
482
{
 
483
  struct http_session *ps = (struct http_session *)handle;
 
484
  enum HTTP_RESULT stat = HTTP_R_IO_ERROR;
 
485
 
 
486
  if(ps && ps->state == HTTP_R_EOF) return HTTP_R_EOF;
 
487
  if(max_size == -1) 
 
488
  { 
 
489
    ps->state = HTTP_R_EOF; 
 
490
    return HTTP_R_EOF; 
 
491
  }
 
492
 
 
493
  DBG("http_read_size() handle=%p data=%p size=%d sectime=%d\n", handle, data, max_size, sec_timeout);
 
494
 
 
495
  *bytes_read=0;
 
496
  while(*bytes_read < max_size)
 
497
  {
 
498
    *((char*)data + (*bytes_read)) = read_char(ps, sec_timeout);
 
499
    *bytes_read = *bytes_read+1;
 
500
  }
 
501
 
 
502
  return stat = HTTP_R_OK;
 
503
}
 
504
 
 
505
/* Write data to HTTP/1.1 connection. Blocks until all data is written or timeout. Caller formats header, footer and payload. */
 
506
enum HTTP_RESULT __attribute__ ((visibility ("hidden"))) http_write(HTTP_HANDLE handle, void *data, int size, int sec_timeout)
 
507
{
 
508
   struct http_session *ps = (struct http_session *)handle;
 
509
   int len; 
 
510
   int tmo=sec_timeout;   /* set initial timeout */
 
511
   enum HTTP_RESULT stat = HTTP_R_IO_ERROR;
 
512
 
 
513
   DBG("http_write() handle=%p data=%p size=%d sectime=%d\n", handle, data, size, sec_timeout);
 
514
 
 
515
   if (hpmud_write_channel(ps->dd, ps->cd, data, size, tmo, &len) != HPMUD_R_OK)
 
516
   {
 
517
      BUG("unable to write channel data\n");
 
518
      goto bugout;
 
519
   }
 
520
 
 
521
   stat = HTTP_R_OK;
 
522
 
 
523
bugout:
 
524
   return stat;
 
525
};
 
526
 
 
527
 
 
528
 
 
529
 
 
530