]> git.ipfire.org Git - thirdparty/cups.git/blob - scripting/java/src/com/easysw/cups/IPPHttp.java
Load cups into easysw/current.
[thirdparty/cups.git] / scripting / java / src / com / easysw / cups / IPPHttp.java
1 package com.easysw.cups;
2
3 /**
4 * @version 1.00 06-NOV-2002
5 * @author Easy Software Products
6 *
7 * Internet Printing Protocol definitions for the Common UNIX Printing
8 * System (CUPS).
9 *
10 * Copyright 1997-2002 by Easy Software Products.
11 *
12 * These coded instructions, statements, and computer programs are the
13 * property of Easy Software Products and are protected by Federal
14 * copyright law. Distribution and use rights are outlined in the file
15 * "LICENSE.txt" which should have been included with this file. If this
16 * file is missing or damaged please contact Easy Software Products
17 * at:
18 *
19 * Attn: CUPS Licensing Information
20 * Easy Software Products
21 * 44141 Airport View Drive, Suite 204
22 * Hollywood, Maryland 20636-3111 USA
23 *
24 * Voice: (301) 373-9603
25 * EMail: cups-info@cups.org
26 * WWW: http://www.cups.org
27 */
28
29 /**
30 * An <code>IPPHttp</code> object is used for reading/writing to the cups
31 * server, and processing responses.
32 *
33 * @author TDB
34 * @version 1.0
35 * @since JDK1.3
36 */
37
38 import java.io.*;
39 import java.util.*;
40 import java.net.*;
41 import java.security.*;
42
43 public class IPPHttp
44 {
45
46 /**
47 * Class constants - most not in use yet.
48 */
49 public static final int HTTP_WAITING = 0x00;
50 public static final int HTTP_OPTIONS = 0x01;
51 public static final int HTTP_GET = 0x02;
52 public static final int HTTP_GET_SEND = 0x03;
53 public static final int HTTP_HEAD = 0x04;
54 public static final int HTTP_POST = 0x05;
55 public static final int HTTP_POST_RECV = 0x06;
56 public static final int HTTP_POST_SEND = 0x07;
57 public static final int HTTP_PUT = 0x08;
58 public static final int HTTP_PUT_RECV = 0x09;
59 public static final int HTTP_DELETE = 0x0A;
60 public static final int HTTP_TRACE = 0x0B;
61 public static final int HTTP_CLOSE = 0x0C;
62 public static final int HTTP_STATUS = 0x0D;
63
64 public static final int HTTP_0_9 = 0x09;
65 public static final int HTTP_1_0 = 0x64;
66 public static final int HTTP_1_1 = 0x65;
67
68 public static final int HTTP_KEEPALIVE_OFF = 0x00;
69 public static final int HTTP_KEEPALIVE_ON = 0x01;
70
71 public static final int HTTP_ENCODE_LENGTH = 0x00;
72 public static final int HTTP_ENCODE_CHUNKED = 0x01;
73
74 public static final int HTTP_ENCRYPT_IF_REQUESTED = 0x00;
75 public static final int HTTP_ENCRYPT_NEVER = 0x01;
76 public static final int HTTP_ENCRYPT_REQUIRED = 0x02;
77 public static final int HTTP_ENCRYPT_ALWAYS = 0x03;
78
79 public static final int HTTP_AUTH_NONE = 0x00;
80 public static final int HTTP_AUTH_BASIC = 0x01;
81 public static final int HTTP_AUTH_MD5 = 0x02;
82 public static final int HTTP_AUTH_MD5_SESS = 0x03;
83 public static final int HTTP_AUTH_MD5_INT = 0x04;
84 public static final int HTTP_AUTH_MD5_SESS_INT = 0x05;
85
86 public static final int HTTP_ERROR = 0xFFFFFFFF;
87 public static final int HTTP_CONTINUE = 0x64;
88 public static final int HTTP_SWITCHING_PROTOCOLS = 0x65;
89 public static final int HTTP_OK = 0xC8;
90 public static final int HTTP_CREATED = 0xC9;
91 public static final int HTTP_ACCEPTED = 0xCA;
92 public static final int HTTP_NOT_AUTHORITATIVE = 0xCB;
93 public static final int HTTP_NO_CONTENT = 0xCC;
94 public static final int HTTP_RESET_CONTENT = 0xCD;
95 public static final int HTTP_PARTIAL_CONTENT = 0xCE;
96 public static final int HTTP_MULTIPLE_CHOICES = 0x12C;
97 public static final int HTTP_MOVED_PERMANENTLY = 0x12D;
98 public static final int HTTP_MOVED_TEMPORARILY = 0x12E;
99 public static final int HTTP_SEE_OTHER = 0x12F;
100 public static final int HTTP_NOT_MODIFIED = 0x130;
101 public static final int HTTP_USE_PROXY = 0x131;
102 public static final int HTTP_BAD_REQUEST = 0x190;
103 public static final int HTTP_UNAUTHORIZED = 0x191;
104 public static final int HTTP_PAYMENT_REQUIRED = 0x192;
105 public static final int HTTP_FORBIDDEN = 0x193;
106 public static final int HTTP_NOT_FOUND = 0x194;
107 public static final int HTTP_METHOD_NOT_ALLOWED = 0x195;
108 public static final int HTTP_NOT_ACCEPTABLE = 0x196;
109 public static final int HTTP_PROXY_AUTHENTICATION = 0x197;
110 public static final int HTTP_REQUEST_TIMEOUT = 0x198;
111 public static final int HTTP_CONFLICT = 0x199;
112 public static final int HTTP_GONE = 0x19A;
113 public static final int HTTP_LENGTH_REQUIRED = 0x19B;
114 public static final int HTTP_PRECONDITION = 0x19C;
115 public static final int HTTP_REQUEST_TOO_LARGE = 0x19D;
116 public static final int HTTP_URI_TOO_LONG = 0x19E;
117 public static final int HTTP_UNSUPPORTED_MEDIATYPE = 0x19F;
118 public static final int HTTP_UPGRADE_REQUIRED = 0x1AA;
119 public static final int HTTP_SERVER_ERROR = 0x1F4;
120 public static final int HTTP_NOT_IMPLEMENTED = 0x1F5;
121 public static final int HTTP_BAD_GATEWAY = 0x1F6;
122 public static final int HTTP_SERVICE_UNAVAILABLE = 0x1F7;
123 public static final int HTTP_GATEWAY_TIMEOUT = 0x1F8;
124
125 public static final int HTTP_NOT_SUPPORTED = 0x1F9;
126
127 public static final int HTTP_FIELD_UNKNOWN = 0xFFFFFFFF;
128 public static final int HTTP_FIELD_ACCEPT_LANGUAGE = 0x00;
129 public static final int HTTP_FIELD_ACCEPT_RANGES = 0x01;
130 public static final int HTTP_FIELD_AUTHORIZATION = 0x02;
131 public static final int HTTP_FIELD_CONNECTION = 0x03;
132 public static final int HTTP_FIELD_CONTENT_ENCODING = 0x04;
133 public static final int HTTP_FIELD_CONTENT_LANGUAGE = 0x05;
134 public static final int HTTP_FIELD_CONTENT_LENGTH = 0x06;
135 public static final int HTTP_FIELD_CONTENT_LOCATION = 0x07;
136 public static final int HTTP_FIELD_CONTENT_MD5 = 0x08;
137 public static final int HTTP_FIELD_CONTENT_RANGE = 0x09;
138 public static final int HTTP_FIELD_CONTENT_TYPE = 0x0A;
139 public static final int HTTP_FIELD_CONTENT_VERSION = 0x0B;
140 public static final int HTTP_FIELD_DATE = 0x0C;
141 public static final int HTTP_FIELD_HOST = 0x0D;
142 public static final int HTTP_FIELD_IF_MODIFIED_SINCE = 0x0E;
143 public static final int HTTP_FIELD_IF_UNMODIFIED_SINCE = 0x0F;
144 public static final int HTTP_FIELD_KEEP_ALIVE = 0x10;
145 public static final int HTTP_FIELD_LAST_MODIFIED = 0x11;
146 public static final int HTTP_FIELD_LINK = 0x12;
147 public static final int HTTP_FIELD_LOCATION = 0x13;
148 public static final int HTTP_FIELD_RANGE = 0x14;
149 public static final int HTTP_FIELD_REFERER = 0x15;
150 public static final int HTTP_FIELD_RETRY_AFTER = 0x16;
151 public static final int HTTP_FIELD_TRANSFER_ENCODING = 0x17;
152 public static final int HTTP_FIELD_UPGRADE = 0x18;
153 public static final int HTTP_FIELD_USER_AGENT = 0x19;
154 public static final int HTTP_FIELD_WWW_AUTHENTICATE = 0x1A;
155 public static final int HTTP_FIELD_MAX = 0x1B;
156
157 public static final String http_fields[] =
158 {
159 "Accept-Language",
160 "Accept-Ranges",
161 "Authorization",
162 "Connection",
163 "Content-Encoding",
164 "Content-Language",
165 "Content-Length",
166 "Content-Location",
167 "Content-MD5",
168 "Content-Range",
169 "Content-Type",
170 "Content-Version",
171 "Date",
172 "Host",
173 "If-Modified-Since",
174 "If-Unmodified-since",
175 "Keep-Alive",
176 "Last-Modified",
177 "Link",
178 "Location",
179 "Range",
180 "Referer",
181 "Retry-After",
182 "Transfer-Encoding",
183 "Upgrade",
184 "User-Agent",
185 "WWW-Authenticate"
186 };
187 public static final String days[] =
188 {
189 "Sun",
190 "Mon",
191 "Tue",
192 "Wed",
193 "Thu",
194 "Fri",
195 "Sat"
196 };
197 public static final String months[] =
198 {
199 "Jan",
200 "Feb",
201 "Mar",
202 "Apr",
203 "May",
204 "Jun",
205 "Jul",
206 "Aug",
207 "Sep",
208 "Oct",
209 "Nov",
210 "Dec"
211 };
212
213
214
215 //
216 // Private class members.
217 //
218 private URL url; // URL of connection.
219
220 public Socket conn; // Connection socket.
221 public boolean connected; // True when connected.
222
223 public BufferedInputStream is; // Input stream.
224 public BufferedReader br;
225 public BufferedOutputStream os; // Output stream.
226
227 private boolean encrypted;
228
229 public int write_content_length;
230 private char write_buffer[];
231 private int write_buffer_head;
232 private int write_buffer_tail;
233
234 public String read_header_date;
235 public String read_header_server;
236 public String read_header_charset;
237 public String read_header_content_language;
238 public String read_header_content_type;
239 public int read_header_content_length;
240
241 public char read_buffer[];
242 private int read_buffer_head;
243 private int read_buffer_tail;
244
245 public int status;
246 public String status_text;
247 public String version;
248 public int error;
249 public int activity;
250
251 public String hostname; // Hostname from URL
252 public int port; // Port from URL.
253 public String path; // Path from URL.
254 public String user; // User name
255 public String passwd; // Password
256
257 public String auth_type; // none, basic, digest
258 public String realm; // For digest auth
259 public String opaque; // For digest auth
260 public String nonce; // For digest auth
261 public String resource; // For digest auth
262 public String method; // For digest auth
263
264 public String http_request;
265 public int http_content_length;
266
267
268
269 /**
270 * Constructor using <code>URL</code>.
271 *
272 * @param request_url <code>URL</code> of server to connect to.
273 * @throw IOException
274 * @throw UnknownHostException
275 */
276 public IPPHttp( String request_url )
277 throws IOException, UnknownHostException
278 {
279
280 encrypted = false;
281 status = 0;
282 status_text = "";
283 version = "1.0";
284 connected = false;
285 user = "";
286 passwd = "";
287
288 auth_type = "";
289 realm = "";
290 nonce = "";
291 resource = "";
292 method = "";
293
294 try
295 {
296 //
297 // Create the URL and split it up.
298 //
299 url = new URL(request_url);
300 hostname = url.getHost();
301 port = url.getPort();
302 path = url.getPath();
303
304
305 //
306 // Open the socket and set the options.
307 //
308 conn = new Socket(hostname, port);
309 conn.setSoTimeout(200);
310
311 //
312 // Create the input and output streams.
313 //
314 is = new BufferedInputStream(new DataInputStream(conn.getInputStream()));
315 os = new BufferedOutputStream(new DataOutputStream(conn.getOutputStream()));
316 connected = true;
317 }
318 catch(UnknownHostException unknownhostexception)
319 {
320 throw unknownhostexception;
321 }
322 catch(IOException ioexception)
323 {
324 throw ioexception;
325 }
326 }
327
328
329
330 /**
331 * Constructor using <code>URL, user and pass</code>.
332 *
333 * @param request_url <code>URL</code> of server to connect to.
334 * @param p_auth_type <code>String</code> basic or digest.
335 * @param p_user <code>String</code> User name.
336 * @param p_passwd <code>String</code> password.
337 * @throw IOException
338 * @throw UnknownHostException
339 */
340 public IPPHttp( String request_url, String p_auth_type,
341 String p_user, String p_passwd )
342 throws IOException, UnknownHostException
343 {
344 encrypted = false;
345 status = 0;
346 status_text = "";
347 version = "1.0";
348 connected = false;
349
350 user = p_user;
351 passwd = p_passwd;
352 auth_type = p_auth_type;
353
354 realm = "";
355 nonce = "";
356 resource = "";
357 method = "";
358
359 try
360 {
361 //
362 // Create the URL and split it up.
363 //
364 url = new URL(request_url);
365 hostname = url.getHost();
366 port = url.getPort();
367 path = url.getPath();
368
369 //
370 // Open the socket and set the options.
371 //
372 conn = new Socket(hostname, port);
373 conn.setSoTimeout(200);
374
375 //
376 // Create the input and output streams.
377 //
378 is = new BufferedInputStream(new DataInputStream(conn.getInputStream()));
379 os = new BufferedOutputStream(new DataOutputStream(conn.getOutputStream()));
380 connected = true;
381 }
382 catch(UnknownHostException unknownhostexception)
383 {
384 throw unknownhostexception;
385 }
386 catch(IOException ioexception)
387 {
388 throw ioexception;
389 }
390 }
391
392
393
394
395 /**
396 * Re-establish a dropped connection.
397 *
398 * @return <code>boolean</code> True if connected.
399 *
400 * @throw IOException
401 */
402 public boolean reConnect() throws IOException
403 {
404 connected = false;
405 status = 0;
406 status_text = "";
407 try
408 {
409 //
410 // Open the socket and set the options.
411 //
412 conn = new Socket(hostname, port);
413 conn.setSoTimeout(200);
414
415 //
416 // Create the input and output streams.
417 //
418 is = new BufferedInputStream(new DataInputStream(conn.getInputStream()));
419 os = new BufferedOutputStream(new DataOutputStream(conn.getOutputStream()));
420 connected = true;
421 return(connected);
422
423 }
424 catch (IOException ioexception)
425 {
426 connected = false;
427 throw(ioexception);
428 }
429 }
430
431
432
433 /**
434 * Set the user name.
435 *
436 * @param p_user <code>String</code> - user name.
437 */
438 public void setUser(String p_user )
439 {
440 user = p_user;
441 }
442
443
444 /**
445 * Set the password.
446 *
447 * @param p_passwd <code>String</code> - password.
448 */
449 public void setPassword(String p_passwd )
450 {
451 passwd = p_passwd;
452 }
453
454
455
456
457 /**
458 * Write the request header bytes to the server.
459 *
460 * @param request <code>String</code> - the request.
461 * @param content_length <code>int</code> - size of the total request.
462 * @throw IOException
463 */
464 public int writeHeader(String request, int content_length )
465 throws IOException
466 {
467
468 http_request = request;
469 http_content_length = content_length;
470
471 try
472 {
473 String s1 = "POST " + request + " HTTP/1.0\r\n";
474 os.write(s1.getBytes(), 0, s1.length());
475
476 s1 = "Content-type: application/ipp\r\n";
477 os.write(s1.getBytes(), 0, s1.length());
478
479
480 //
481 // Do basic style authorization if needed.
482 //
483 if (auth_type.compareTo("basic") == 0)
484 {
485 s1 = user + ":" + passwd;
486 IPPBase64Encoder encoder = new IPPBase64Encoder();
487 String auth_string = encoder.encode(s1.getBytes());
488 s1 = "Authorization: Basic " + auth_string + "\r\n";
489 os.write(s1.getBytes(), 0, s1.length());
490 }
491 else if (auth_type.compareTo("digest") == 0)
492 {
493 try
494 {
495 IPPMD5 md5 = IPPMD5.getInstance();
496 String auth_string = md5.MD5Digest(user, passwd, realm,
497 "POST", path, nonce );
498 s1 = "Authorization: Digest " + "username=\"" + user + "\", " +
499 "realm=\"" + realm + "\", " +
500 "nonce=\"" + nonce + "\", " +
501 "response=\"" + auth_string + "\"\r\n";
502
503 os.write(s1.getBytes(), 0, s1.length());
504 }
505 catch(NoSuchAlgorithmException e)
506 {
507 System.out.println("No such algorithm: MD5.");
508 }
509 }
510
511 s1 = "Content-length: " + content_length + "\r\n\r\n";
512 os.write(s1.getBytes(), 0, s1.length());
513 os.flush();
514 }
515 catch(IOException ioexception)
516 {
517 error = HTTP_ERROR;
518 throw ioexception;
519 }
520
521
522 try
523 {
524 int local_status = 0;
525
526 //
527 // Check for any response.
528 //
529 if (is.available() > 0)
530 {
531 StringBuffer http_version = new StringBuffer(32);
532 StringBuffer http_status = new StringBuffer(32);
533 StringBuffer http_text = new StringBuffer(256);
534
535 String read_buffer;
536 status = 0;
537 is.mark(8192);
538 while (is.available() > 0)
539 {
540 read_buffer = read_line();
541
542 if (read_buffer.startsWith("HTTP/"))
543 {
544 int i,n;
545 String s2 = read_buffer.substring(5);
546
547
548 for (i=0;(i < s2.length() && s2.charAt(i) != ' '); i++)
549 {
550 http_version.append(s2.charAt(i));
551 }
552 while (i < s2.length() && s2.charAt(i) == ' ')
553 i++;
554 for (;(i < s2.length() && s2.charAt(i) != '\n' &&
555 s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++)
556 {
557 http_status.append(s2.charAt(i));
558 }
559
560 while (i < s2.length() && s2.charAt(i) == ' ')
561 i++;
562 for (n=0;(n < 256 && i < s2.length() && s2.charAt(i) != '\n' &&
563 s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++)
564 {
565 http_text.append(s2.charAt(i));
566 }
567 local_status = Integer.parseInt(http_status.toString(), 10);
568 }
569 }
570 is.reset();
571 }
572
573 //
574 // See if we need to reconnect and send authorization.
575 //
576 switch( local_status )
577 {
578 //
579 // Not authorized.
580 //
581 case HTTP_UNAUTHORIZED: read_header();
582 return( local_status );
583 }
584 }
585 catch(IOException ioexception)
586 {
587 error = HTTP_ERROR;
588 throw ioexception;
589 }
590 return(0);
591 }
592
593
594
595
596
597
598 public int checkForResponse()
599 {
600 //
601 // Check for any response.
602 //
603 try
604 {
605 if (is.available() > 0)
606 {
607 StringBuffer http_version = new StringBuffer(32);
608 StringBuffer http_status = new StringBuffer(32);
609 StringBuffer http_text = new StringBuffer(256);
610 int local_status = 0;
611 String read_buffer;
612
613 status = 0;
614 is.mark(8192);
615 while (is.available() > 0)
616 {
617 read_buffer = read_line();
618 if (read_buffer.startsWith("HTTP/"))
619 {
620 int i,n;
621 String s2 = read_buffer.substring(5);
622 for (i=0;(i < s2.length() && s2.charAt(i) != ' '); i++)
623 {
624 http_version.append(s2.charAt(i));
625 }
626 while (i < s2.length() && s2.charAt(i) == ' ')
627 i++;
628 for (;(i < s2.length() && s2.charAt(i) != '\n' &&
629 s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++)
630 {
631 http_status.append(s2.charAt(i));
632 }
633
634 while (i < s2.length() && s2.charAt(i) == ' ')
635 i++;
636 for (n=0;(n < 256 && i < s2.length() && s2.charAt(i) != '\n' &&
637 s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++)
638 {
639 http_text.append(s2.charAt(i));
640 }
641 local_status = Integer.parseInt(http_status.toString(), 10);
642 status = local_status;
643 }
644 }
645 is.reset();
646
647 //
648 // See if we need to reconnect and send authorization.
649 //
650 switch( local_status )
651 {
652 //
653 // Not authorized.
654 //
655 case HTTP_UNAUTHORIZED: read_header();
656 return( local_status );
657 }
658 }
659 }
660 catch (IOException e)
661 {
662 return(HTTP_ERROR);
663 }
664 return(0);
665 }
666
667
668 /**
669 * Write bytes to the output stream.
670 *
671 * @param bytes Array of bytes to write to the stream.
672 * @throw IOException
673 */
674 public void write(byte bytes[])
675 throws IOException
676 {
677 try
678 {
679 os.write(bytes, 0, bytes.length);
680 os.flush();
681 }
682 catch(IOException ioexception)
683 {
684 error = HTTP_ERROR;
685 throw ioexception;
686 }
687 }
688
689
690 /**
691 * Write bytes to the output stream.
692 *
693 * @param bytes Array of bytes to write to the stream.
694 * @param length Number of bytes to write to the stream.
695 * @throw IOException
696 */
697 public void write(byte bytes[], int length )
698 throws IOException
699 {
700 try
701 {
702 os.write(bytes, 0, length);
703 os.flush();
704 }
705 catch(IOException ioexception)
706 {
707 error = HTTP_ERROR;
708 throw ioexception;
709 }
710 }
711
712
713
714
715
716
717
718
719
720
721 /**
722 * Read the HTTP header from the input stream.
723 *
724 * @return <code>int</code> Content length of response.
725 * @return 0 Return zero on error.
726 * @throw IOException
727 */
728 public int read_header()
729 throws IOException
730 {
731 boolean done = false;
732 read_header_content_length = 0;
733
734 String read_buffer;
735 while (!done)
736 {
737 read_buffer = read_line();
738 if (read_buffer.startsWith("HTTP/"))
739 {
740 int i,n;
741 String s2 = read_buffer.substring(5);
742
743 StringBuffer http_version = new StringBuffer(32);
744 StringBuffer http_status = new StringBuffer(32);
745 StringBuffer http_text = new StringBuffer(256);
746
747 for (i=0;(i < s2.length() && s2.charAt(i) != ' '); i++)
748 {
749 http_version.append(s2.charAt(i));
750 }
751 while (i < s2.length() && s2.charAt(i) == ' ')
752 i++;
753 for (;(i < s2.length() && s2.charAt(i) != '\n' &&
754 s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++)
755 {
756 http_status.append(s2.charAt(i));
757 }
758
759 while (i < s2.length() && s2.charAt(i) == ' ')
760 i++;
761 for (n=0;(n < 256 && i < s2.length() && s2.charAt(i) != '\n' &&
762 s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++)
763 {
764 http_text.append(s2.charAt(i));
765 }
766 version = http_version.toString();
767 status = Integer.parseInt(http_status.toString(), 10);
768 status_text = http_text.toString();
769 }
770 else if (read_buffer.startsWith("WWW-Authenticate: Basic"))
771 {
772 String s2=read_buffer.substring("WWW-Authenticate: Basic".length());
773 auth_type = "basic";
774 }
775 else if (read_buffer.startsWith("WWW-Authenticate: Digest"))
776 {
777 String s2=read_buffer.substring("WWW-Authenticate: Digest".length());
778 auth_type = "digest";
779 parseAuthenticate(s2);
780 }
781 else if (read_buffer.startsWith("Content-Length:"))
782 {
783 String s2 = read_buffer.substring(15);
784 read_header_content_length = Integer.parseInt(s2.trim(), 10);
785 }
786 else if (read_buffer.startsWith("Content-Language:"))
787 {
788 String s3 = read_buffer.substring(17);
789 read_header_content_language = s3.trim();
790 }
791 else if (read_buffer.startsWith("Server:"))
792 {
793 String s4 = read_buffer.substring(7);
794 read_header_server = s4.trim();
795 }
796 else if (read_buffer.startsWith("Date:"))
797 {
798 String s5 = read_buffer.substring(5);
799 read_header_date = s5.trim();
800 }
801 else if (read_buffer.length() == 0)
802 {
803 done = true;
804 return( read_header_content_length );
805 }
806 }
807 return( 0 );
808 }
809
810
811
812 /**
813 * Read a line from the input stream.
814 *
815 * @return <code>String</code> Line read.
816 * @throw <code>IOException</code>
817 */
818 public String read_line()
819 throws IOException
820 {
821 StringBuffer sb = new StringBuffer();
822 int c = 0;
823
824 try
825 {
826 while ((c != -1) && (c != 10))
827 {
828 c = is.read();
829 switch( c )
830 {
831 case -1:
832 case 10:
833 case 13:
834 break;
835
836 default: sb.append((char)c);
837 }
838 }
839 }
840 catch (IOException e)
841 {
842 throw(e);
843 }
844 return(sb.toString());
845 }
846
847
848
849
850
851 /**
852 * Read up to <code>count</code> bytes from the input stream.
853 *
854 * @param <code>count</code> Number of bytes to read.
855 * @return <code>char[]</code> Character array of data read.
856 * @throw <code>IOException</code>
857 */
858 public char[] read(int count)
859 throws IOException
860 {
861 char ac[] = new char[count];
862 int j = 0;
863 try
864 {
865 for (int k = is.read(); k != -1 && j < count; k = is.read())
866 {
867 ac[j++] = (char)k;
868 }
869 }
870 catch(IOException ioexception)
871 {
872 throw ioexception;
873 }
874 return(ac);
875 }
876
877
878 /**
879 * Process the HTTP response from the server.
880 *
881 * @return <code>IPP</code> IPP object containing response data.
882 * @see <code>IPP</code>
883 * @see <code>IPPRequest</code>
884 * @see <code>IPPAttribute</code>
885 * @see <code>IPPValue</code>
886 * @see <code>IPPDefs</code>
887 */
888 public IPP processResponse()
889 {
890 IPP ipp;
891 IPPAttribute attr; // temp attribute
892 IPPValue val; // temp value
893
894 short vtag; // Current value tag
895 short gtag; // Current group tag
896
897 char[] buffer;
898
899 ipp = new IPP();
900 ipp.request = new IPPRequest();
901
902 int read_buffer_bytes = read_buffer.length;
903 int read_buffer_remaining = read_buffer_bytes;
904 int bufferidx = 0;
905 int n;
906
907
908 ipp.current = -1; // current attritue??
909 ipp.last = -1; // last attr?
910 attr = null;
911 buffer = read_buffer;
912 gtag = -1;
913 vtag = -1;
914
915
916 // ---------------------------------------------------------------
917 // State machine to process response.
918 //
919 ipp.state = IPPDefs.IDLE;
920 while ((ipp.state != IPPDefs.TAG_END) &&
921 (read_buffer_remaining > 0))
922 {
923 switch (ipp.state)
924 {
925 case IPPDefs.IDLE :
926 ipp.state++; /* Avoid common problem... */
927
928 //
929 // Get the request header...
930 //
931 case IPPDefs.HEADER :
932 if (read_buffer_remaining < 8)
933 {
934 return (null);
935 }
936
937 //
938 // Verify the major version number...
939 //
940 if (buffer[0] != (char)1)
941 {
942 return (null);
943 }
944
945 //
946 // Then copy the request header over...
947 //
948 ipp.request.version[0] = buffer[bufferidx++];
949 ipp.request.version[1] = buffer[bufferidx++];
950 ipp.request.op_status = (short)((short)buffer[bufferidx] << 8) |
951 (short)buffer[bufferidx+1];
952 bufferidx += 2;
953
954 //
955 // Get the text version of the request status ....
956 //
957 ipp.status = new IPPStatus(ipp.request.op_status);
958
959 ipp.request.request_id = (int)((int)buffer[bufferidx] << 24) |
960 ((int)buffer[bufferidx+1] << 16) |
961 ((int)buffer[bufferidx+2] << 8) |
962 ((int)buffer[bufferidx+3]);
963 bufferidx += 4;
964 read_buffer_remaining -= 8;
965
966 ipp.state = IPPDefs.ATTRIBUTE;
967 ipp.current = -1;
968 ipp.current_tag = IPPDefs.TAG_ZERO;
969 break;
970
971 case IPPDefs.ATTRIBUTE :
972 while (read_buffer_remaining > 0)
973 {
974 //
975 // Read the value tag first.
976 //
977 vtag = (short)buffer[bufferidx++];
978 read_buffer_remaining--;
979 if (vtag == IPPDefs.TAG_END)
980 {
981 //
982 // No more attributes left...
983 //
984 ipp.state = IPPDefs.DATA;
985 if (attr != null)
986 {
987 ipp.addAttribute(attr);
988 attr = null;
989 }
990 break;
991 }
992 else if (vtag < IPPDefs.TAG_UNSUPPORTED_VALUE)
993 {
994 if (attr != null)
995 {
996 ipp.addAttribute(attr);
997 }
998
999 //
1000 // Group tag... Set the current group and continue...
1001 //
1002 gtag = vtag;
1003
1004 // If still the same group ....
1005 if (ipp.current_tag == gtag)
1006 {
1007 //
1008 // Add a separator
1009 //
1010 attr = new IPPAttribute(IPPDefs.TAG_ZERO,IPPDefs.TAG_ZERO,"");
1011 ipp.addAttribute(attr);
1012 attr = null;
1013 }
1014
1015
1016 ipp.current_tag = gtag;
1017 ipp.current = -1;
1018 continue;
1019 }
1020
1021 //
1022 // Get the name...
1023 //
1024 n = ((int)buffer[bufferidx] << 8) | (int)buffer[bufferidx+1];
1025 bufferidx += 2;
1026 read_buffer_remaining -= 2;
1027
1028 if (n == 0)
1029 {
1030 //
1031 // Parse Error, can't add additional values to null attr
1032 //
1033 if (attr == null)
1034 return (null);
1035
1036 //
1037 // More values for current attribute...
1038 //
1039
1040 //
1041 // Make sure we aren't adding a new value of a different
1042 // type...
1043 //
1044
1045 if (attr.value_tag == IPPDefs.TAG_STRING ||
1046 (attr.value_tag >= IPPDefs.TAG_TEXTLANG &&
1047 attr.value_tag <= IPPDefs.TAG_MIMETYPE))
1048 {
1049 //
1050 // String values can sometimes come across in different
1051 // forms; accept sets of differing values...
1052 //
1053 if (vtag != IPPDefs.TAG_STRING &&
1054 (vtag < IPPDefs.TAG_TEXTLANG || vtag > IPPDefs.TAG_MIMETYPE))
1055 return (null);
1056 }
1057 else if (attr.value_tag != vtag)
1058 return (null);
1059 }
1060 else
1061 {
1062 if (attr != null)
1063 {
1064 ipp.addAttribute(attr);
1065 attr = null;
1066 }
1067
1068 //
1069 // New Attribute
1070 //
1071 StringBuffer s = new StringBuffer();
1072 for (int i=0; i < n; i++)
1073 {
1074 s.append((char)buffer[bufferidx++]);
1075 read_buffer_remaining--;
1076 }
1077 attr = new IPPAttribute( gtag, vtag, s.toString() );
1078 }
1079 n = ((short)buffer[bufferidx] << 8) | (short)buffer[bufferidx+1];
1080 bufferidx += 2;
1081 read_buffer_remaining -= 2;
1082
1083 switch (vtag)
1084 {
1085 case IPPDefs.TAG_INTEGER :
1086 case IPPDefs.TAG_ENUM :
1087 n = (int)(((int)buffer[bufferidx] << 24) |
1088 ((int)buffer[bufferidx+1] << 16) |
1089 ((int)buffer[bufferidx+2] << 8) |
1090 ((int)buffer[bufferidx+3]));
1091 bufferidx += 4;
1092 read_buffer_remaining -= 4;
1093 attr.addInteger( n );
1094 break;
1095
1096 case IPPDefs.TAG_BOOLEAN :
1097 if ((byte)buffer[bufferidx++] > 0)
1098 attr.addBoolean(true);
1099 else
1100 attr.addBoolean(false);
1101 read_buffer_remaining --;
1102 break;
1103
1104 case IPPDefs.TAG_TEXT :
1105 case IPPDefs.TAG_NAME :
1106 case IPPDefs.TAG_KEYWORD :
1107 case IPPDefs.TAG_STRING :
1108 case IPPDefs.TAG_URI :
1109 case IPPDefs.TAG_URISCHEME :
1110 case IPPDefs.TAG_CHARSET :
1111 case IPPDefs.TAG_LANGUAGE :
1112 case IPPDefs.TAG_MIMETYPE :
1113 StringBuffer s = new StringBuffer();
1114 for (int i=0; i < n; i++ )
1115 {
1116 s.append( (char)buffer[bufferidx++] );
1117 read_buffer_remaining --;
1118 }
1119 attr.addString( "", s.toString() );
1120 break;
1121
1122
1123 case IPPDefs.TAG_DATE :
1124 char db[] = new char[11];
1125 for (int i=0; i < 11; i++ )
1126 {
1127 db[i] = (char)buffer[bufferidx++];
1128 read_buffer_remaining --;
1129 }
1130 attr.addDate( db );
1131 break;
1132
1133
1134 case IPPDefs.TAG_RESOLUTION :
1135 if (read_buffer_remaining < 9)
1136 return( null );
1137
1138 int x, y;
1139 byte u;
1140 x = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) |
1141 (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) |
1142 (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) |
1143 (((int)buffer[bufferidx+3] & 0x000000ff));
1144 bufferidx += 4;
1145 read_buffer_remaining -= 4;
1146
1147 y = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) |
1148 (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) |
1149 (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) |
1150 (((int)buffer[bufferidx+3] & 0x000000ff));
1151 bufferidx += 4;
1152 read_buffer_remaining -= 4;
1153
1154 u = (byte)buffer[bufferidx++];
1155 read_buffer_remaining--;
1156 attr.addResolution( u, x, y );
1157 break;
1158
1159 case IPPDefs.TAG_RANGE :
1160 if (read_buffer_remaining < 8)
1161 return (null);
1162
1163 int lower, upper;
1164 lower = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) |
1165 (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) |
1166 (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) |
1167 (((int)buffer[bufferidx+3] & 0x000000ff));
1168 bufferidx += 4;
1169 read_buffer_remaining -= 4;
1170
1171 upper = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) |
1172 (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) |
1173 (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) |
1174 (((int)buffer[bufferidx+3] & 0x000000ff));
1175 bufferidx += 4;
1176 read_buffer_remaining -= 4;
1177
1178 attr.addRange( (short)lower, (short)upper );
1179 break;
1180
1181 case IPPDefs.TAG_TEXTLANG :
1182 case IPPDefs.TAG_NAMELANG :
1183 //
1184 // text-with-language and name-with-language are composite
1185 // values:
1186 //
1187 // charset-length
1188 // charset
1189 // text-length
1190 // text
1191 //
1192
1193 n = ((int)buffer[bufferidx] << 8) | (int)buffer[bufferidx+1];
1194 bufferidx += 2;
1195
1196 StringBuffer cs = new StringBuffer();
1197 for (int i=0; i < n; i++ )
1198 {
1199 cs.append( (char)buffer[bufferidx++] );
1200 read_buffer_remaining --;
1201 }
1202
1203 n = ((int)buffer[bufferidx] << 8) | (int)buffer[bufferidx+1];
1204 bufferidx += 2;
1205
1206 StringBuffer tx = new StringBuffer();
1207 for (int i=0; i < n; i++ )
1208 {
1209 tx.append( (char)buffer[bufferidx++] );
1210 read_buffer_remaining --;
1211 }
1212
1213 attr.addString( cs.toString(), tx.toString() );
1214 break;
1215
1216
1217 default : /* Other unsupported values */
1218 if (n > 0)
1219 {
1220 bufferidx += n;
1221 read_buffer_remaining -= n;
1222 }
1223 break;
1224 }
1225 } // End of while
1226
1227 if (attr != null)
1228 {
1229 ipp.addAttribute(attr);
1230 attr = null;
1231 }
1232 break;
1233
1234 case IPPDefs.DATA :
1235 break;
1236
1237 default :
1238 break; /* anti-compiler-warning-code */
1239 }
1240 }
1241 return (ipp);
1242 }
1243
1244
1245
1246 //
1247 // Parse a WWW-Authenticate: Digest request
1248 //
1249 public void parseAuthenticate( String p_auth )
1250 {
1251 String tmp;
1252 StringBuffer val;
1253 int i,n;
1254
1255 tmp = p_auth;
1256 while (tmp.length() > 0)
1257 {
1258 i = 0;
1259 while (tmp.length() > 0 && (tmp.charAt(i) == ' ' || tmp.charAt(i) == '"'))
1260 tmp = tmp.substring(1);
1261 i = 0;
1262
1263 if (tmp.startsWith("realm="))
1264 {
1265 i = "realm=".length();
1266 tmp = tmp.substring(i);
1267 i = 0;
1268 while ((i < tmp.length()) &&
1269 (tmp.charAt(i) == ' ' ||
1270 tmp.charAt(i) == '"' ||
1271 tmp.charAt(i) == '='))
1272 {
1273 i++;
1274 }
1275 val = new StringBuffer(1024);
1276 while (i < tmp.length() && tmp.charAt(i) != '"')
1277 val.append(tmp.charAt(i++));
1278 realm = val.toString();
1279 tmp = tmp.substring(i);
1280 }
1281 else if (tmp.startsWith("nonce="))
1282 {
1283 i = "nonce=".length();
1284 tmp = tmp.substring(i);
1285 i = 0;
1286 while ((i < tmp.length()) &&
1287 (tmp.charAt(i) == ' ' ||
1288 tmp.charAt(i) == '"' ||
1289 tmp.charAt(i) == '='))
1290 {
1291 i++;
1292 }
1293 val = new StringBuffer(1024);
1294 while (i < tmp.length() && tmp.charAt(i) != '"')
1295 val.append(tmp.charAt(i++));
1296 nonce = val.toString();
1297 tmp = tmp.substring(i);
1298 }
1299 else if (tmp.startsWith("opaque="))
1300 {
1301 i = "opaque=".length();
1302 tmp = tmp.substring(i);
1303 i = 0;
1304 while ((i < tmp.length()) &&
1305 (tmp.charAt(i) == ' ' ||
1306 tmp.charAt(i) == '"' ||
1307 tmp.charAt(i) == '='))
1308 {
1309 i++;
1310 }
1311 val = new StringBuffer(1024);
1312 while (i < tmp.length() && tmp.charAt(i) != '"')
1313 val.append(tmp.charAt(i++));
1314 opaque = val.toString();
1315 tmp = tmp.substring(i);
1316 }
1317 else
1318 {
1319 StringBuffer name = new StringBuffer(256);
1320 while ((i < tmp.length()) &&
1321 (tmp.charAt(i) != ' ' ||
1322 tmp.charAt(i) != '"' ||
1323 tmp.charAt(i) != '='))
1324 {
1325 name.append(tmp.charAt(i++));
1326 }
1327
1328 i = name.toString().length();
1329 tmp = tmp.substring(i);
1330 i = 0;
1331 while ((i < tmp.length()) &&
1332 (tmp.charAt(i) == ' ' ||
1333 tmp.charAt(i) == '"' ||
1334 tmp.charAt(i) == '='))
1335 {
1336 i++;
1337 }
1338 val = new StringBuffer(1024);
1339 while (i < tmp.length() && tmp.charAt(i) != '"')
1340 val.append(tmp.charAt(i++));
1341 //junk = val.toString();
1342 tmp = tmp.substring(i);
1343 }
1344 }
1345 }
1346
1347
1348
1349
1350
1351 } // End of IPPHttp class
1352
1353