KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcraft > jhttptunnel > JHttpTunnelServer


1 /* -*-mode:java; c-basic-offset:2; -*- */
2 /*
3 Copyright (c) 2004 ymnk, JCraft,Inc. All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8   1. Redistributions of source code must retain the above copyright notice,
9      this list of conditions and the following disclaimer.
10
11   2. Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in
13      the documentation and/or other materials provided with the distribution.
14
15   3. The names of the authors may not be used to endorse or promote products
16      derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
21 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */

29
30 package com.jcraft.jhttptunnel;
31 import java.lang.*;
32 import java.io.*;
33 import java.net.*;
34 import java.util.*;
35
36 public class JHttpTunnelServer extends Thread JavaDoc{
37
38   static int connections=0;
39   static int client_connections=0;
40   static int source_connections=0;
41
42   private ServerSocket serverSocket=null;
43   static int port=8888;
44   static String JavaDoc myaddress=null;
45   static String JavaDoc myURL=null;
46
47   static String JavaDoc default_host;
48   static int default_port;
49
50   JHttpTunnelServer(int port){
51     super();
52     connections=0;
53     try{ serverSocket=new ServerSocket(port); }
54     catch(IOException e){
55       //System.out.println("ServerSocket error"+e );
56
System.exit(1);
57     }
58     try{
59       if(myaddress==null)
60         myURL="http://"+InetAddress.getLocalHost().getHostAddress()+":"+port;
61       else
62         myURL="http://"+myaddress+":"+port;
63       //System.out.println("myURL: "+myURL);
64
}
65     catch(Exception JavaDoc e){
66       System.out.println(e );
67     }
68   }
69   JHttpTunnelServer(int lport, String JavaDoc fhost, int fport){
70     this(lport);
71     this.default_host=fhost;
72     this.default_port=fport;
73   }
74
75   public void run(){
76     Socket socket=null;
77     while(true){
78       try{socket=serverSocket.accept();}
79       catch(IOException e) {
80     System.out.println("accept error");
81     System.exit(1);
82       }
83       connections++;
84       //new Spawn(socket);
85
final Socket _socket=socket;
86       new Thread JavaDoc(new Runnable JavaDoc(){
87     public void run(){
88       try{(new Dispatch(_socket)).doit();}
89       catch(Exception JavaDoc e){}
90     }
91     }).start();
92     }
93   }
94
95   /*
96   class Spawn extends Thread{
97     private Socket socket=null;
98     Spawn(Socket socket){
99       super();
100       this.socket=socket;
101       start();
102     }
103     public void run(){
104       try{(new Dispatch(socket)).doit();}
105       catch(Exception e){}
106     }
107   }
108   */

109
110   public static void main(String JavaDoc[] arg){
111
112     int port=8888;
113     if(arg.length!=0){
114       String JavaDoc _port=arg[0];
115       if(_port!=null){
116     port=Integer.parseInt(_port);
117       }
118     }
119
120     String JavaDoc fhost=null;
121     int fport=0;
122     String JavaDoc _fw=System.getProperty("F");
123     if(_fw!=null && _fw.indexOf(':')!=-1){
124       fport=Integer.parseInt(_fw.substring(_fw.lastIndexOf(':') + 1));
125       fhost=_fw.substring(0, _fw.lastIndexOf(':'));
126     }
127     if(fport==0 || fhost==null){
128       System.err.println("forward-port is not given");
129       System.exit(1);
130     }
131     (new JHttpTunnelServer(port, fhost, fport)).start();
132   }
133 }
134  
135 class Dispatch{
136   private MySocket mySocket=null;
137   private String JavaDoc rootDirectory=".";
138   private String JavaDoc defaultFile="index.html";
139
140   Dispatch(Socket s) throws IOException{
141     super();
142     mySocket=new MySocket(s);
143   }
144
145   private Vector getHttpHeader(MySocket ms) throws IOException{
146     Vector v=new Vector();
147     String JavaDoc foo=null;
148     while(true){
149       foo=ms.readLine();
150       if(foo.length()==0){ break; }
151       v.addElement(foo);
152     }
153     return v;
154   }
155
156   byte[] buf=new byte[1024];
157
158   private void procPOST(String JavaDoc string, Vector httpheader) throws IOException{
159     String JavaDoc foo;
160     int len=0;
161     int c;
162     String JavaDoc file=string.substring(string.indexOf(' ') + 1);
163     if(file.indexOf(' ')!=-1)
164       file=file.substring(0 , file.indexOf(' '));
165
166     Hashtable vars=getVars((file.indexOf('?')!=-1)?
167                file.substring(file.indexOf('?')+1):null);
168     String JavaDoc sid=(String JavaDoc)vars.get("SESSIONID");
169
170     Client client=null;
171     if(sid==null){
172       sid=new Long JavaDoc(System.currentTimeMillis()).toString();
173       client=new Client(sid,
174             JHttpTunnelServer.default_host,
175             JHttpTunnelServer.default_port);
176     }
177     else{
178       client=getClient(sid);
179     }
180
181     //System.out.println("client: "+client);
182

183     if(client==null){
184       notFound(mySocket);
185       return;
186     }
187
188     for(int i=0; i<httpheader.size(); i++){
189       foo=(String JavaDoc)httpheader.elementAt(i);
190       if(foo.startsWith("Content-Length:") ||
191      foo.startsWith("Content-length:") // hmm... for Opera, lynx
192
){
193     foo=foo.substring(foo.indexOf(' ')+1);
194     foo=foo.trim();
195     len=Integer.parseInt(foo);
196       }
197     }
198
199     //System.out.println("len: "+len);
200

201     if(len==0){ // just read data
202
client.command=-1;
203       client.dataremain=0;
204     }
205
206     if(client.dataremain==0 && len>0){
207       int i=mySocket.read(buf, 0, 1); // command
208
len--;
209       client.command=buf[0];
210       int datalen=0;
211
212       if((client.command&JHttpTunnel.TUNNEL_SIMPLE)==0){
213     i=mySocket.read(buf, 0, 2);
214     len-=2;
215     if(i!=2){
216     }
217     datalen=(((buf[0])<<8)&0xff00);
218     datalen=datalen|(buf[1]&0xff);
219       }
220 //System.out.println("command: "+client.command+" "+datalen);
221
client.dataremain=datalen;
222     }
223
224 //System.out.println("dataremain: "+client.dataremain+" len="+len);
225

226     int i=0;
227     if(len>0){
228       i=mySocket.read(buf, 0, len);
229 //System.out.println("["+new String(buf, 0, i)+"]");
230
client.dataremain-=len;
231     }
232
233     if(client.dataremain==0){
234 System.out.println(sid+": "+client.command);
235       switch(client.command){
236         case JHttpTunnel.TUNNEL_OPEN:
237       client.connect();
238       break;
239         case JHttpTunnel.TUNNEL_DATA:
240       client.send(buf, 0, len);
241       break;
242         case JHttpTunnel.TUNNEL_CLOSE:
243       client.close();
244       break;
245       }
246     }
247
248     i=0;
249     if(client.isConnected()){
250       i=client.pop(buf, 3, buf.length-3);
251       if(i>0){
252     buf[0]=JHttpTunnel.TUNNEL_DATA;
253     buf[1]=(byte)((i>>>8)&0xff);
254     buf[2]=(byte)(i&0xff);
255     i+=3;
256       }
257     }
258     ok(mySocket, buf, 0, i, sid);
259   }
260
261   private void procGET(String JavaDoc string, Vector httpheader) throws IOException{
262     String JavaDoc foo;
263     int c;
264     String JavaDoc file=string.substring(string.indexOf(' ') + 1);
265     if(file.indexOf(' ')!=-1)
266       file=file.substring(0 , file.indexOf(' '));
267
268     if(file.indexOf("..")!=-1){
269       notFound(mySocket);
270       return;
271     }
272
273     if(file.startsWith("/"))
274       file=file.substring(1);
275
276     try {
277       File _file=new File(file);
278       int len=(int)_file.length();
279       FileInputStream fis=new FileInputStream(file);
280       ok(mySocket, fis, len, null);
281       fis.close();
282     }
283     catch(IOException e){
284       System.out.println(e);
285     }
286
287
288   }
289
290   private void procHEAD(String JavaDoc string, Vector httpheader) throws IOException{
291     ok(mySocket, null, 0, 0, "");
292   }
293
294   String JavaDoc decode(String JavaDoc arg){
295     byte[] foo=arg.getBytes();
296     StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
297     for(int i=0; i<foo.length; i++){
298       if(foo[i]=='+'){ sb.append((char)' '); continue; }
299       if(foo[i]=='%' && i+2<foo.length){
300         int bar=foo[i+1];
301         bar=('0'<=bar && bar<='9')? bar-'0' :
302       ('a'<=bar && bar<='z')? bar-'a'+10 :
303       ('A'<=bar && bar<='Z')? bar-'A'+10 : bar;
304         bar*=16;
305         int goo=foo[i+2];
306         goo=('0'<=goo && goo<='9')? goo-'0' :
307       ('a'<=goo && goo<='f')? goo-'a'+10 :
308       ('A'<=goo && goo<='F')? goo-'A'+10 : goo;
309         bar+=goo; bar&=0xff;
310         sb.append((char)bar);
311         i+=2;
312         continue;
313       }
314       sb.append((char)foo[i]);
315     }
316     return sb.toString();
317   }
318
319   Hashtable getVars(String JavaDoc arg){
320     Hashtable vars=new Hashtable();
321     if(arg==null) return vars;
322     arg=decode(arg);
323     int foo=0;
324     int i=0;
325     int c=0;
326     String JavaDoc key, value;
327     while(true){
328       key=value=null;
329       foo=arg.indexOf('=');
330       if(foo==-1)break;
331       key=arg.substring(0, foo);
332       arg=arg.substring(foo+1);
333       foo=arg.indexOf('&');
334       if(foo!=-1){
335         value=arg.substring(0, foo);
336         arg=arg.substring(foo+1);
337       }
338       else value=arg;
339       vars.put(key, value);
340       if(foo==-1)break;
341     }
342     return vars;
343   }
344
345   public void doit(){
346     try{
347       String JavaDoc foo=mySocket.readLine();
348
349 System.out.println(mySocket.socket.getInetAddress()+": "+foo+" "+(new java.util.Date JavaDoc()));
350
351       if(foo.indexOf(' ')==-1){
352         mySocket.close();
353         return;
354       }
355
356       String JavaDoc bar=foo.substring(0, foo.indexOf(' '));
357       //System.out.println(foo);
358

359       Vector v=getHttpHeader(mySocket);
360
361 //System.out.println(v);
362

363       if(bar.equalsIgnoreCase("POST")){
364         procPOST(foo, v);
365         return;
366       }
367
368       if(bar.equalsIgnoreCase("GET")){
369         procGET(foo, v);
370         return;
371       }
372
373       if(bar.equalsIgnoreCase("HEAD")){
374         procHEAD(foo, v);
375         return;
376       }
377     }
378     catch(Exception JavaDoc e){
379     }
380   }
381
382   void ok(MySocket mysocket, byte[] buf, int s, int l, String JavaDoc sid) throws IOException{
383     mysocket.println("HTTP/1.1 200 OK");
384     mysocket.println("Last-Modified: Thu, 04 Oct 2001 14:09:23 GMT");
385     if(sid!=null){
386       mysocket.println("x-SESSIONID: "+sid);
387     }
388     mysocket.println("Content-Length: "+l);
389     mysocket.println("Connection: close");
390     mysocket.println("Content-Type: text/html; charset=iso-8859-1");
391     mysocket.println("");
392
393     if(l>0){
394       mysocket.write(buf, s, l);
395     }
396
397     mysocket.flush();
398     mysocket.close();
399   }
400
401   void ok(MySocket mysocket, InputStream in, int l, String JavaDoc sid) throws IOException{
402     mysocket.println("HTTP/1.1 200 OK");
403     mysocket.println("Last-Modified: Thu, 04 Oct 2001 14:09:23 GMT");
404     if(sid!=null){
405       mysocket.println("x-SESSIONID: "+sid);
406     }
407     mysocket.println("Content-Length: "+l);
408     mysocket.println("Connection: close");
409     mysocket.println("Content-Type: text/html; charset=iso-8859-1");
410     mysocket.println("");
411
412     if(l>0){
413       byte[] buf=new byte[1024];
414       while(true){
415     int i=in.read(buf, 0, buf.length);
416     if(i<0) break;
417     if(i>0){
418       mysocket.write(buf, 0, i);
419     }
420       }
421     }
422     mysocket.flush();
423     mysocket.close();
424   }
425
426
427   static void notFound(MySocket ms) throws IOException{
428     ms.println("HTTP/1.1 404 Not Found") ;
429     ms.println("Content-Type: text/html") ;
430     ms.println("Content-Length: 0");
431     ms.println("Connection: close");
432     ms.println("") ;
433     ms.flush();
434     ms.close();
435   }
436
437   private static Hashtable cpool=new Hashtable();
438   static Client getClient(String JavaDoc sid){ return (Client)cpool.get(sid); }
439   static void putClient(String JavaDoc sid, Client client){ cpool.put(sid, client); }
440   static void removeClient(String JavaDoc sid){ cpool.remove(sid); }
441
442   class Client extends Thread JavaDoc{
443
444     private String JavaDoc sid;
445     private String JavaDoc host;
446     private int port;
447
448     Client(String JavaDoc sid, String JavaDoc host, int port){
449       super();
450       this.sid=sid;
451       this.host=host;
452       this.port=port;
453       putClient(sid, this);
454     }
455
456     public int dataremain=0;
457     public byte command=0;
458
459     private Socket socket=null;
460     private InputStream in;
461     private OutputStream out;
462
463     boolean connected=false;
464
465     boolean isConnected(){
466       return connected;
467     }
468
469     void connect(){
470       try{
471     socket=new Socket(host, port);
472 //System.out.println("socket: "+socket);
473
in=socket.getInputStream();
474     out=socket.getOutputStream();
475     connected=true;
476     start();
477       }
478       catch(Exception JavaDoc e){
479     System.out.println(e);
480       }
481     }
482
483     public void send(byte[] foo, int s, int l){
484 //System.out.println("send: "+new String(foo, s, l));
485
try{
486     out.write(foo, s, l);
487     out.flush();
488       }
489       catch(Exception JavaDoc e){
490     System.out.println(e);
491       }
492     }
493
494     public void run(){
495       byte[] buf=new byte[1024];
496       while(true){
497     try{
498       int space=space();
499           if(space>0){
500         if(space>buf.length)space=buf.length;
501         int i=in.read(buf, 0, space);
502 //System.out.println("run read: "+i);
503
if(i<0){
504               break;
505         }
506 //System.out.println(new String(buf, 0, i));
507
if(i>0){
508           push(buf, 0, i);
509           try{ Thread.sleep(1); }
510           catch(Exception JavaDoc ee){}
511           continue;
512         }
513       }
514       while(true){
515         if(space()>0) break;
516         try{ Thread.sleep(1000); }
517         catch(Exception JavaDoc ee){
518         }
519       }
520     }
521     catch(java.net.SocketException JavaDoc e){
522       //System.out.println(e);
523
break;
524     }
525     catch(Exception JavaDoc e){
526       //System.out.println(e);
527
}
528       }
529       close();
530     }
531
532     int buflen=0;
533 // byte[] buf=new byte[1024];
534
// byte[] buf=new byte[4096];
535
byte[] buf=new byte[10240];
536     synchronized int space(){
537 //System.out.println("space "+(buf.length-buflen));
538
return buf.length-buflen;
539     }
540     synchronized void push(byte[] foo, int s, int l){
541 //System.out.println("push "+l);
542
System.arraycopy(foo, s, buf, buflen, l);
543       buflen+=l;
544     }
545     synchronized int pop(byte[] foo, int s, int l){
546       if(buflen==0){
547 //System.out.println("pop "+0);
548
return 0;
549       }
550       if(l>buflen)l=buflen;
551       System.arraycopy(buf, 0, foo, s, l);
552       System.arraycopy(buf, l, buf, 0, buflen-l);
553       buflen-=l;
554
555       if(socket==null && buflen<=0){
556     removeClient(sid);
557       }
558 //System.out.println("pop: "+l);
559
return l;
560     }
561
562     public void close(){
563       try{
564     in.close();
565     out.close();
566     socket.close();
567     socket=null;
568       }
569       catch(Exception JavaDoc e){
570       }
571       if(buflen==0){
572     removeClient(sid);
573       }
574     }
575
576   }
577 }
578
Popular Tags