KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xmlrpc > WebServer


1 /*
2  * Copyright 1999,2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17
18 package org.apache.xmlrpc;
19
20 import java.io.BufferedInputStream JavaDoc;
21 import java.io.BufferedOutputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InterruptedIOException JavaDoc;
24 import java.io.UnsupportedEncodingException JavaDoc;
25 import java.net.BindException JavaDoc;
26 import java.net.InetAddress JavaDoc;
27 import java.net.ServerSocket JavaDoc;
28 import java.net.Socket JavaDoc;
29 import java.net.SocketException JavaDoc;
30 import java.util.EmptyStackException JavaDoc;
31 import java.util.Stack JavaDoc;
32 import java.util.StringTokenizer JavaDoc;
33 import java.util.Vector JavaDoc;
34 import org.apache.commons.codec.binary.Base64;
35
36 /**
37  * A minimal web server that exclusively handles XML-RPC requests.
38  *
39  * @author <a HREF="mailto:hannes@apache.org">Hannes Wallnoefer</a>
40  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
41  * @author Daniel L. Rall
42  */

43 public class WebServer implements Runnable JavaDoc
44 {
45     protected XmlRpcServer xmlrpc;
46
47     protected ServerSocket JavaDoc serverSocket;
48     protected Thread JavaDoc listener;
49     protected Vector JavaDoc accept, deny;
50     protected Stack JavaDoc threadpool;
51     protected ThreadGroup JavaDoc runners;
52
53     // Inputs to setupServerSocket()
54
private InetAddress JavaDoc address;
55     private int port;
56
57     private boolean paranoid;
58
59     protected static final byte[] ctype =
60         toHTTPBytes("Content-Type: text/xml\r\n");
61     protected static final byte[] clength =
62         toHTTPBytes("Content-Length: ");
63     protected static final byte[] newline = toHTTPBytes("\r\n");
64     protected static final byte[] doubleNewline = toHTTPBytes("\r\n\r\n");
65     protected static final byte[] conkeep =
66         toHTTPBytes("Connection: Keep-Alive\r\n");
67     protected static final byte[] conclose =
68         toHTTPBytes("Connection: close\r\n");
69     protected static final byte[] ok = toHTTPBytes(" 200 OK\r\n");
70     protected static final byte[] server =
71         toHTTPBytes("Server: Apache XML-RPC 1.0\r\n");
72     protected static final byte[] wwwAuthenticate =
73         toHTTPBytes("WWW-Authenticate: Basic realm=XML-RPC\r\n");
74
75     private static final String JavaDoc HTTP_11 = "HTTP/1.1";
76     private static final String JavaDoc STAR = "*";
77
78     /**
79      * This <em>can</em> be called from command line, but you'll have to edit
80      * and recompile to change the server port or handler objects. By default,
81      * it sets up the following responders:
82      * <ul>
83      * <li> A java.lang.String object </li>
84      * <li> The java.lang.Math class (making its static methods callable via
85      * XML-RPC) </li>
86      * <li> An Echo handler that returns the argument array </li>
87      * </ul>
88      *
89      * @see #addDefaultHandlers()
90      */

91     public static void main(String JavaDoc[] argv)
92     {
93         int p = determinePort(argv, 8080);
94         // XmlRpc.setDebug (true);
95
XmlRpc.setKeepAlive(true);
96         WebServer webserver = new WebServer(p);
97
98         try
99         {
100             webserver.addDefaultHandlers();
101             webserver.start();
102         }
103         catch (Exception JavaDoc e)
104         {
105             System.err.println("Error running web server");
106             e.printStackTrace();
107             System.exit(1);
108         }
109     }
110
111     /**
112      * Examines command line arguments from <code>argv</code>. If a
113      * port may have been provided, parses that port (exiting with
114      * error status if the port cannot be parsed). If no port is
115      * specified, defaults to <code>defaultPort</code>.
116      *
117      * @param defaultPort The port to use if none was specified.
118      */

119     protected static int determinePort(String JavaDoc[] argv, int defaultPort)
120     {
121         int port = defaultPort;
122         if (argv.length > 0)
123         {
124             try
125             {
126                 port = Integer.parseInt(argv[0]);
127             }
128             catch (NumberFormatException JavaDoc nfx)
129             {
130                 System.err.println("Error parsing port number: " + argv[0]);
131                 System.err.println("Usage: java " + WebServer.class.getName()
132                                    + " [port]");
133                 System.exit(1);
134             }
135         }
136         return port;
137     }
138
139     /**
140      * Creates a web server at the specified port number.
141      */

142     public WebServer(int port)
143     {
144         this(port, null);
145     }
146
147     /**
148      * Creates a web server at the specified port number and IP address.
149      */

150     public WebServer(int port, InetAddress JavaDoc addr)
151     {
152         this(port, addr, new XmlRpcServer());
153     }
154
155     /**
156      * Creates a web server at the specified port number and IP
157      * address.
158      */

159     public WebServer(int port, InetAddress JavaDoc addr, XmlRpcServer xmlrpc)
160     {
161         this.address = addr;
162         this.port = port;
163         this.xmlrpc = xmlrpc;
164         accept = new Vector JavaDoc();
165         deny = new Vector JavaDoc();
166         threadpool = new Stack JavaDoc();
167         runners = new ThreadGroup JavaDoc("XML-RPC Runner");
168     }
169
170     /**
171      * Returns the US-ASCII encoded byte representation of text for
172      * HTTP use (as per section 2.2 of RFC 2068).
173      */

174     protected static final byte[] toHTTPBytes(String JavaDoc text)
175     {
176         try
177         {
178             return text.getBytes("US-ASCII");
179         }
180         catch (UnsupportedEncodingException JavaDoc e)
181         {
182             throw new Error JavaDoc(e.getMessage() +
183                             ": HTTP requires US-ASCII encoding");
184         }
185     }
186
187     /**
188      * Factory method to manufacture the server socket. Useful as a
189      * hook method for subclasses to override when they desire
190      * different flavor of socket (i.e. a <code>SSLServerSocket</code>).
191      *
192      * @param port
193      * @param backlog
194      * @param addr If <code>null</code>, binds to
195      * <code>INADDR_ANY</code>, meaning that all network interfaces on
196      * a multi-homed host will be listening.
197      * @exception Exception Error creating listener socket.
198      */

199     protected ServerSocket JavaDoc createServerSocket(int port, int backlog,
200             InetAddress JavaDoc addr)
201             throws Exception JavaDoc
202     {
203         return new ServerSocket JavaDoc(port, backlog, addr);
204     }
205
206     /**
207      * Initializes this server's listener socket with the specified
208      * attributes, assuring that a socket timeout has been set. The
209      * {@link #createServerSocket(int, int, InetAddress)} method can
210      * be overridden to change the flavor of socket used.
211      *
212      * @see #createServerSocket(int, int, InetAddress)
213      */

214     private synchronized void setupServerSocket(int backlog)
215             throws Exception JavaDoc
216     {
217         // Since we can't reliably set SO_REUSEADDR until JDK 1.4 is
218
// the standard, try to (re-)open the server socket several
219
// times. Some OSes (Linux and Solaris, for example), hold on
220
// to listener sockets for a brief period of time for security
221
// reasons before relinquishing their hold.
222
int attempt = 1;
223         while (serverSocket == null)
224         {
225             try
226             {
227                 serverSocket = createServerSocket(port, backlog, address);
228             }
229             catch (BindException JavaDoc e)
230             {
231                 if (attempt == 10)
232                 {
233                     throw e;
234                 }
235
236                 attempt++;
237                 Thread.sleep(1000);
238             }
239         }
240
241         if (XmlRpc.debug)
242         {
243             StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
244             msg.append("Opened XML-RPC server socket for ");
245             msg.append(address != null ? address.getHostName() : "localhost");
246             msg.append(':').append(port);
247             if (attempt > 1)
248             {
249                 msg.append(" after ").append(attempt).append(" tries");
250             }
251             System.out.println(msg.toString());
252         }
253
254         // A socket timeout must be set.
255
if (serverSocket.getSoTimeout() <= 0)
256         {
257             serverSocket.setSoTimeout(4096);
258         }
259     }
260
261     /**
262      * Spawns a new thread which binds this server to the port it's
263      * configured to accept connections on.
264      *
265      * @see #run()
266      */

267     public void start()
268     {
269         try
270         {
271             setupServerSocket(50);
272         }
273         catch (Exception JavaDoc e)
274         {
275             listener = null;
276             e.printStackTrace();
277             throw new RuntimeException JavaDoc(e.getMessage());
278         }
279
280         // The listener reference is released upon shutdown().
281
if (listener == null)
282         {
283             listener = new Thread JavaDoc(this, "XML-RPC Weblistener");
284             // Not marked as daemon thread since run directly via main().
285
listener.start();
286         }
287     }
288
289     /**
290      * Register a handler object with this name. Methods of this objects will be
291      * callable over XML-RPC as "name.method".
292      */

293     public void addHandler(String JavaDoc name, Object JavaDoc target)
294     {
295         xmlrpc.addHandler(name, target);
296     }
297
298     /**
299      * Adds the bundled handlers to the server. Called by {@link
300      * #main(String[])}.
301      */

302     protected void addDefaultHandlers()
303         throws Exception JavaDoc
304     {
305         // webserver.setParanoid (true);
306
// webserver.acceptClient ("192.168.*.*");
307
addHandler("string", "Welcome to XML-RPC!");
308         addHandler("math", Math JavaDoc.class);
309         addHandler("auth", new AuthDemo());
310         addHandler("$default", new Echo());
311         // XmlRpcClients can be used as Proxies in XmlRpcServers which is a
312
// cool feature for applets.
313
String JavaDoc url = "http://www.mailtothefuture.com:80/RPC2";
314         addHandler("mttf", new XmlRpcClient(url));
315         SystemHandler system = new SystemHandler();
316         system.addDefaultSystemHandlers();
317         addHandler("system", system);
318     }
319
320     /**
321      * Remove a handler object that was previously registered with this server.
322      */

323     public void removeHandler(String JavaDoc name)
324     {
325         xmlrpc.removeHandler(name);
326     }
327
328     /**
329      * Switch client filtering on/off.
330      * @see #acceptClient(java.lang.String)
331      * @see #denyClient(java.lang.String)
332      */

333     public void setParanoid(boolean p)
334     {
335         paranoid = p;
336     }
337
338     /**
339      * Add an IP address to the list of accepted clients. The parameter can
340      * contain '*' as wildcard character, e.g. "192.168.*.*". You must call
341      * setParanoid(true) in order for this to have any effect.
342      *
343      * @see #denyClient(java.lang.String)
344      * @see #setParanoid(boolean)
345      */

346     public void acceptClient(String JavaDoc address) throws IllegalArgumentException JavaDoc
347     {
348         try
349         {
350             AddressMatcher m = new AddressMatcher(address);
351             accept.addElement(m);
352         }
353         catch (Exception JavaDoc x)
354         {
355             throw new IllegalArgumentException JavaDoc("\"" + address
356                     + "\" does not represent a valid IP address");
357         }
358     }
359
360     /**
361      * Add an IP address to the list of denied clients. The parameter can
362      * contain '*' as wildcard character, e.g. "192.168.*.*". You must call
363      * setParanoid(true) in order for this to have any effect.
364      *
365      * @see #acceptClient(java.lang.String)
366      * @see #setParanoid(boolean)
367      */

368     public void denyClient(String JavaDoc address) throws IllegalArgumentException JavaDoc
369     {
370         try
371         {
372             AddressMatcher m = new AddressMatcher(address);
373             deny.addElement(m);
374         }
375         catch (Exception JavaDoc x)
376         {
377             throw new IllegalArgumentException JavaDoc("\"" + address
378                     + "\" does not represent a valid IP address");
379         }
380     }
381
382     /**
383      * Checks incoming connections to see if they should be allowed.
384      * If not in paranoid mode, always returns true.
385      *
386      * @param s The socket to inspect.
387      * @return Whether the connection should be allowed.
388      */

389     protected boolean allowConnection(Socket JavaDoc s)
390     {
391         if (!paranoid)
392         {
393             return true;
394         }
395
396         int l = deny.size();
397         byte address[] = s.getInetAddress().getAddress();
398         for (int i = 0; i < l; i++)
399         {
400             AddressMatcher match = (AddressMatcher)deny.elementAt(i);
401             if (match.matches(address))
402             {
403                 return false;
404             }
405         }
406         l = accept.size();
407         for (int i = 0; i < l; i++)
408         {
409             AddressMatcher match = (AddressMatcher)accept.elementAt(i);
410             if (match.matches(address))
411             {
412                 return true;
413             }
414         }
415         return false;
416     }
417
418     /**
419      * DEPRECATED: Do not use this method, it will be removed soon.
420      * Use {@link #allowConnection(Socket)} instead.
421      *
422      * @deprecated Use allowConnection(Socket) instead.
423      * @see #allowConnection(Socket)
424      */

425     protected boolean checkSocket(Socket JavaDoc s)
426     {
427         return allowConnection(s);
428     }
429
430     /**
431      * Listens for client requests until stopped. Call {@link
432      * #start()} to invoke this method, and {@link #shutdown()} to
433      * break out of it.
434      *
435      * @throws RuntimeException Generally caused by either an
436      * <code>UnknownHostException</code> or <code>BindException</code>
437      * with the vanilla web server.
438      *
439      * @see #start()
440      * @see #shutdown()
441      */

442     public void run()
443     {
444         try
445         {
446             while (listener != null)
447             {
448                 try
449                 {
450                     Socket JavaDoc socket = serverSocket.accept();
451                     try
452                     {
453                         socket.setTcpNoDelay(true);
454                     }
455                     catch (SocketException JavaDoc socketOptEx)
456                     {
457                         System.err.println(socketOptEx);
458                     }
459
460                     if (allowConnection(socket))
461                     {
462                         Runner runner = getRunner();
463                         runner.handle(socket);
464                     }
465                     else
466                     {
467                         socket.close();
468                     }
469                 }
470                 catch (InterruptedIOException JavaDoc checkState)
471                 {
472                     // Timeout while waiting for a client (from
473
// SO_TIMEOUT)...try again if still listening.
474
}
475                 catch (Exception JavaDoc ex)
476                 {
477                     System.err.println("Exception in XML-RPC listener loop ("
478                             + ex + ").");
479                     if (XmlRpc.debug)
480                     {
481                         ex.printStackTrace();
482                     }
483                 }
484                 catch (Error JavaDoc err)
485                 {
486                     System.err.println("Error in XML-RPC listener loop ("
487                             + err + ").");
488                     err.printStackTrace();
489                 }
490             }
491         }
492         catch (Exception JavaDoc exception)
493         {
494             System.err.println("Error accepting XML-RPC connections ("
495                     + exception + ").");
496             if (XmlRpc.debug)
497             {
498                 exception.printStackTrace();
499             }
500         }
501         finally
502         {
503             if (serverSocket != null)
504             {
505                 try
506                 {
507                     serverSocket.close();
508                     if (XmlRpc.debug)
509                     {
510                         System.out.print("Closed XML-RPC server socket");
511                     }
512                     serverSocket = null;
513                 }
514                 catch (IOException JavaDoc e)
515                 {
516                     e.printStackTrace();
517                 }
518             }
519
520             // Shutdown our Runner-based threads
521
if (runners != null)
522             {
523                 ThreadGroup JavaDoc g = runners;
524                 runners = null;
525                 try
526                 {
527                     g.interrupt();
528                 }
529                 catch (Exception JavaDoc e)
530                 {
531                     System.err.println(e);
532                     e.printStackTrace();
533                 }
534             }
535         }
536     }
537
538     /**
539      * Stop listening on the server port. Shutting down our {@link
540      * #listener} effectively breaks it out of its {@link #run()}
541      * loop.
542      *
543      * @see #run()
544      */

545     public synchronized void shutdown()
546     {
547         // Stop accepting client connections
548
if (listener != null)
549         {
550             Thread JavaDoc l = listener;
551             listener = null;
552             l.interrupt();
553         }
554     }
555
556     /**
557      *
558      * @return
559      */

560     protected Runner getRunner()
561     {
562         try
563         {
564             return (Runner)threadpool.pop();
565         }
566         catch (EmptyStackException JavaDoc empty)
567         {
568             int maxRequests = XmlRpc.getMaxThreads();
569             if (runners.activeCount() > XmlRpc.getMaxThreads())
570             {
571                 throw new RuntimeException JavaDoc("System overload: Maximum number " +
572                                            "of concurrent requests (" +
573                                            maxRequests + ") exceeded");
574             }
575             return new Runner();
576         }
577     }
578
579     /**
580      * Put <code>runner</code> back into {@link #threadpool}.
581      *
582      * @param runner The instance to reclaim.
583      */

584     void repoolRunner(Runner runner)
585     {
586         threadpool.push(runner);
587     }
588
589     /**
590      * Responsible for handling client connections.
591      */

592     class Runner implements Runnable JavaDoc
593     {
594         Thread JavaDoc thread;
595         Connection con;
596         int count;
597
598         /**
599          * Handles the client connection on <code>socket</code>.
600          *
601          * @param socket The source to read the client's request from.
602          */

603         public synchronized void handle(Socket JavaDoc socket) throws IOException JavaDoc
604         {
605             con = new Connection(socket);
606             count = 0;
607             if (thread == null || !thread.isAlive())
608             {
609                 thread = new Thread JavaDoc(runners, this);
610                 thread.start();
611             }
612             else
613             {
614                 // Wake the thread waiting in our run() method.
615
this.notify();
616             }
617         }
618
619         /**
620          * Delegates to <code>con.run()</code>.
621          */

622         public void run()
623         {
624             while (con != null && Thread.currentThread() == thread)
625             {
626                 con.run();
627                 count++;
628                 con = null;
629
630                 if (count > 200 || threadpool.size() > 20)
631                 {
632                     // We're old, or the number of threads in the pool
633
// is large.
634
return;
635                 }
636                 synchronized(this)
637                 {
638                     repoolRunner(this);
639                     try
640                     {
641                         this.wait();
642                     }
643                     catch (InterruptedException JavaDoc ir)
644                     {
645                         Thread.currentThread().interrupt();
646                     }
647                 }
648             }
649         }
650     }
651
652     /**
653      *
654      */

655     class Connection implements Runnable JavaDoc
656     {
657         private Socket JavaDoc socket;
658         private BufferedInputStream JavaDoc input;
659         private BufferedOutputStream JavaDoc output;
660         private String JavaDoc user, password;
661         private Base64 base64Codec;
662         byte[] buffer;
663
664         /**
665          *
666          * @param socket
667          * @throws IOException
668          */

669         public Connection (Socket JavaDoc socket) throws IOException JavaDoc
670         {
671             // set read timeout to 30 seconds
672
socket.setSoTimeout (30000);
673
674             this.socket = socket;
675             input = new BufferedInputStream JavaDoc(socket.getInputStream());
676             output = new BufferedOutputStream JavaDoc(socket.getOutputStream());
677         }
678
679         /**
680          *
681          */

682         public void run()
683         {
684             try
685             {
686                 boolean keepAlive = false;
687
688                 do
689                 {
690                     // reset user authentication
691
user = null;
692                     password = null;
693                     String JavaDoc line = readLine();
694                     // Netscape sends an extra \n\r after bodypart, swallow it
695
if (line != null && line.length() == 0)
696                     {
697                         line = readLine();
698                     }
699                     if (XmlRpc.debug)
700                     {
701                         System.out.println(line);
702                     }
703                     int contentLength = -1;
704
705                     // tokenize first line of HTTP request
706
StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(line);
707                     String JavaDoc method = tokens.nextToken();
708                     String JavaDoc uri = tokens.nextToken();
709                     String JavaDoc httpVersion = tokens.nextToken();
710                     keepAlive = XmlRpc.getKeepAlive()
711                             && HTTP_11.equals(httpVersion);
712                     do
713                     {
714                         line = readLine();
715                         if (line != null)
716                         {
717                             if (XmlRpc.debug)
718                             {
719                                 System.out.println(line);
720                             }
721                             String JavaDoc lineLower = line.toLowerCase();
722                             if (lineLower.startsWith("content-length:"))
723                             {
724                                 contentLength = Integer.parseInt(
725                                         line.substring(15).trim());
726                             }
727                             if (lineLower.startsWith("connection:"))
728                             {
729                                 keepAlive = XmlRpc.getKeepAlive() &&
730                                         lineLower.indexOf("keep-alive") > -1;
731                             }
732                             if (lineLower.startsWith("authorization: basic "))
733                             {
734                                 parseAuth (line);
735                             }
736                         }
737                     }
738                     while (line != null && line.length() != 0);
739
740                     if ("POST".equalsIgnoreCase(method))
741                     {
742                         ServerInputStream sin = new ServerInputStream(input,
743                                 contentLength);
744                         try
745                         {
746                             byte[] result = xmlrpc.execute(sin, user, password);
747                             writeResponse(result, httpVersion, keepAlive);
748                         }
749                         catch (AuthenticationFailed unauthorized)
750                         {
751                             keepAlive = false;
752                             writeUnauthorized(httpVersion, method);
753                         }
754                     }
755                     else
756                     {
757                         keepAlive = false;
758                         writeBadRequest(httpVersion, method);
759                     }
760                     output.flush();
761                 }
762                 while (keepAlive);
763             }
764             catch (Exception JavaDoc exception)
765             {
766                 if (XmlRpc.debug)
767                 {
768                     exception.printStackTrace();
769                 }
770                 else
771                 {
772                     System.err.println(exception);
773                 }
774             }
775             finally
776             {
777                 try
778                 {
779                     if (socket != null)
780                     {
781                         socket.close();
782                     }
783                 }
784                 catch (IOException JavaDoc ignore)
785                 {
786                 }
787             }
788         }
789
790         /**
791          *
792          * @return
793          * @throws IOException
794          */

795         private String JavaDoc readLine() throws IOException JavaDoc
796         {
797             if (buffer == null)
798             {
799                 buffer = new byte[2048];
800             }
801             int next;
802             int count = 0;
803             for (;;)
804             {
805                 next = input.read();
806                 if (next < 0 || next == '\n')
807                 {
808                     break;
809                 }
810                 if (next != '\r')
811                 {
812                     buffer[count++] = (byte) next;
813                 }
814                 if (count >= buffer.length)
815                 {
816                     throw new IOException JavaDoc("HTTP Header too long");
817                 }
818             }
819             return new String JavaDoc(buffer, 0, count);
820         }
821
822         /**
823          *
824          * @param line
825          */

826         private void parseAuth(String JavaDoc line)
827         {
828             try
829             {
830                 byte[] c = base64Codec.decode(toHTTPBytes(line.substring(21)));
831                 String JavaDoc str = new String JavaDoc(c);
832                 int col = str.indexOf(':');
833                 user = str.substring(0, col);
834                 password = str.substring(col + 1);
835             }
836             catch (Throwable JavaDoc ignore)
837             {
838             }
839         }
840
841         private void writeResponse(byte[] payload, String JavaDoc httpVersion,
842                                    boolean keepAlive)
843             throws IOException JavaDoc
844         {
845             output.write(toHTTPBytes(httpVersion));
846             output.write(ok);
847             output.write(server);
848             output.write(keepAlive ? conkeep : conclose);
849             output.write(ctype);
850             output.write(clength);
851             output.write(toHTTPBytes(Integer.toString(payload.length)));
852             output.write(doubleNewline);
853             output.write(payload);
854         }
855
856         private void writeBadRequest(String JavaDoc httpVersion, String JavaDoc httpMethod)
857             throws IOException JavaDoc
858         {
859             output.write(toHTTPBytes(httpVersion));
860             output.write(toHTTPBytes(" 400 Bad Request"));
861             output.write(newline);
862             output.write(server);
863             output.write(newline);
864             output.write(toHTTPBytes("Method " + httpMethod +
865                                      " not implemented (try POST)"));
866         }
867
868         private void writeUnauthorized(String JavaDoc httpVersion, String JavaDoc httpMethod)
869             throws IOException JavaDoc
870         {
871             output.write(toHTTPBytes(httpVersion));
872             output.write(toHTTPBytes(" 401 Unauthorized"));
873             output.write(newline);
874             output.write(server);
875             output.write(wwwAuthenticate);
876             output.write(newline);
877             output.write(toHTTPBytes("Method " + httpMethod + " requires a " +
878                                      "valid user name and password"));
879         }
880     }
881
882     /**
883      *
884      */

885     class AddressMatcher
886     {
887         int pattern[];
888
889         /**
890          *
891          * @param address
892          * @throws Exception
893          */

894         public AddressMatcher(String JavaDoc address) throws Exception JavaDoc
895         {
896             pattern = new int[4];
897             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(address, ".");
898             if (st.countTokens() != 4)
899             {
900                 throw new Exception JavaDoc("\"" + address
901                         + "\" does not represent a valid IP address");
902             }
903             for (int i = 0; i < 4; i++)
904             {
905                 String JavaDoc next = st.nextToken();
906                 if (STAR.equals(next))
907                 {
908                     pattern[i] = 256;
909                 }
910                 else
911                 {
912                     pattern[i] = (byte) Integer.parseInt(next);
913                 }
914             }
915         }
916
917         /**
918          *
919          * @param address
920          * @return
921          */

922         public boolean matches (byte address[])
923         {
924             for (int i = 0; i < 4; i++)
925             {
926                 if (pattern[i] > 255)// wildcard
927
{
928                     continue;
929                 }
930                 if (pattern[i] != address[i])
931                 {
932                     return false;
933                 }
934             }
935             return true;
936         }
937     }
938 }
939
Popular Tags