Work around Tomcat/AJP bug.
[jsvc.git] / src / dolda / jsvc / j2ee / J2eeRequest.java
1 package dolda.jsvc.j2ee;
2
3 import dolda.jsvc.*;
4 import dolda.jsvc.util.*;
5 import java.io.*;
6 import java.util.*;
7 import java.net.*;
8 import javax.servlet.*;
9 import javax.servlet.http.*;
10
11 public class J2eeRequest extends ResponseBuffer {
12     private ServletConfig cfg;
13     private HttpServletRequest req;
14     private HttpServletResponse resp;
15     private String method, path;
16     private URL url, context;
17     private MultiMap<String, String> params = null;
18     private Map<Object, Object> props = new HashMap<Object, Object>();
19     
20     public J2eeRequest(ServletConfig cfg, HttpServletRequest req, HttpServletResponse resp) {
21         this.cfg = cfg;
22         this.req = req;
23         this.resp = resp;
24         {
25             /* Ewwww, this is disgusting! */
26             String scheme = req.getScheme();
27             int port = -1;
28             String host = req.getHeader("Host");
29             if((host == null) || (host.length() < 1)) {
30                 host = req.getLocalAddr();
31                 port = req.getLocalPort();
32                 if((port == 80) && scheme.equals("http"))
33                     port = -1;
34                 else if((port == 443) && scheme.equals("https"))
35                     port = -1;
36             } else {
37                 int p;
38                 if((host.charAt(0) == '[') && ((p = host.indexOf(']', 1)) > 1)) {
39                     String newhost = host.substring(1, p);
40                     if((p = host.indexOf(':', p + 1)) >= 0) {
41                         try {
42                             port = Integer.parseInt(host.substring(p + 1));
43                         } catch(NumberFormatException e) {}
44                     }
45                     host = newhost;
46                 } else if((p = host.indexOf(':')) >= 0) {
47                     try {
48                         port = Integer.parseInt(host.substring(p + 1));
49                         host = host.substring(0, p);
50                     } catch(NumberFormatException e) {}
51                 }
52             }
53             String pi = req.getPathInfo();
54             if(pi == null)
55                 pi = "";
56             String q = req.getQueryString();
57             if(q != null)
58                 q = "?" + q;
59             else
60                 q = "";
61             try {
62                 url = new URL(scheme, host, port, req.getContextPath() + req.getServletPath() + pi + q);
63                 context = new URL(scheme, host, port, req.getContextPath());
64             } catch(MalformedURLException e) {
65                 throw(new Error(e));
66             }
67         }
68         method = req.getMethod().toUpperCase().intern();
69         path = req.getPathInfo();
70         while((path.length() > 0) && (path.charAt(0) == '/'))
71             path = path.substring(1);
72     }
73     
74     public Map<Object, Object> props() {
75         return(props);
76     }
77     
78     public SocketAddress remoteaddr() {
79         try {
80             /* Apparently getRemotePort returns -1 when running on Tomcat over AJP. */
81             int port = req.getRemotePort();
82             if(port < 0)
83                 port = 0;
84             return(new InetSocketAddress(InetAddress.getByName(req.getRemoteAddr()), port));
85         } catch(UnknownHostException e) {
86             /* req.getRemoteAddr should always be a valid IP address,
87              * so this should never happen. */
88             throw(new Error(e));
89         }
90     }
91     
92     public SocketAddress localaddr() {
93         try {
94             return(new InetSocketAddress(InetAddress.getByName(req.getLocalAddr()), req.getLocalPort()));
95         } catch(UnknownHostException e) {
96             /* req.getRemoteAddr should always be a valid IP address,
97              * so this should never happen. */
98             throw(new Error(e));
99         }
100     }
101     
102     public URL url() {
103         return(url);
104     }
105     
106     public URL rooturl() {
107         return(context);
108     }
109     
110     public ServerContext ctx() {
111         return(ThreadContext.current().server());
112     }
113     
114     public String method() {
115         return(method);
116     }
117     
118     public String path() {
119         return(path);
120     }
121
122     public InputStream input() {
123         try {
124             return(req.getInputStream());
125         } catch(IOException e) {
126             /* It is not obvious why this would happen, so I'll wait
127              * until I know whatever might happen to try and implement
128              * meaningful behavior. */
129             throw(new RuntimeException(e));
130         }
131     }
132
133     public MultiMap<String, String> inheaders() {
134         MultiMap<String, String> h = new HeaderTreeMap();
135         Enumeration ki = req.getHeaderNames();
136         if(ki != null) {
137             while(ki.hasMoreElements()) {
138                 String k = (String)ki.nextElement();
139                 Enumeration vi = req.getHeaders(k);
140                 if(vi != null) {
141                     while(vi.hasMoreElements()) {
142                         String v = (String)vi.nextElement();
143                         h.add(k, v);
144                     }
145                 }
146             }
147         }
148         return(h);
149     }
150     
151     public MultiMap<String, String> params() {
152         if(params == null) {
153             params = Params.urlparams(this);
154             if(method == "POST") {
155                 MultiMap<String, String> pp = Params.postparams(this);
156                 if(pp != null)
157                     params.putAll(pp);
158             }
159         }
160         return(params);
161     }
162     
163     protected void backflush() {
164         resp.setStatus(respcode);
165         for(String key : outheaders().keySet()) {
166             boolean first = true;
167             for(String val : outheaders().values(key)) {
168                 if(first) {
169                     resp.setHeader(key, val);
170                     first = false;
171                 } else {
172                     resp.addHeader(key, val);
173                 }
174             }
175         }
176     }
177     
178     protected OutputStream realoutput() {
179         try {
180             return(resp.getOutputStream());
181         } catch(IOException e) {
182             /* It is not obvious why this would happen, so I'll wait
183              * until I know whatever might happen to try and implement
184              * meaningful behavior. */
185             throw(new RuntimeException(e));
186         }
187     }
188 }