001: /*
002: * $Id: HTTPResponse.java,v 1.12 2005/11/30 11:27:21 ss150821 Exp $
003: * $Source: /m/portal/ps/srap/src/com/sun/portal/rproxy/connectionhandler/HTTPResponse.java,v $
004: * $Log: HTTPResponse.java,v $
005: * Revision 1.12 2005/11/30 11:27:21 ss150821
006: * 6356996 - Srap Code base needs to save files in the unix file format and not windows
007: *
008: * Revision 1.11 2005/02/24 07:36:44 ss150821
009: * RFE 6223490 - SRA Should use JDK based logging
010: *
011: * Revision 1.10 2005/02/23 09:15:05 ss150821
012: * RFE 6223490 - SRA Should use JDK based logging
013: *
014: * Revision 1.9 2005/02/05 02:03:33 ss150821
015: * Bug #5037296 - issues in accessing portal on bea cluster through gateway from IE
016: *
017: * Revision 1.8 2003/07/08 13:54:44 mm132998
018: * Custom header support : Bug 4788933
019: *
020: * Revision 1.7 2003/04/24 11:07:55 mm132998
021: * Client caching : 4831618
022: *
023: * Revision 1.6 2003/04/15 05:28:20 mm132998
024: * WebDAV support
025: *
026: * Revision 1.5 2003/03/28 06:58:49 rt130506
027: * MAP Fixes
028: *
029: * Revision 1.4 2003/03/27 13:27:58 bv131302
030: * Escalation 544720 fix
031: *
032: * Revision 1.3 2002/08/21 07:36:18 bv131302
033: * Fixes for 4681457, 4703696, 4713296, 4718232, 4726004, 4726008
034: *
035: * Revision 1.2 2002/07/19 11:22:07 ss133690
036: * CRT : 1677 return to login page with should work with Hana on SSL
037: *
038: * Revision 1.1 2002/06/14 09:53:52 rt130506
039: * SRAP rebranding
040: *
041: * Revision 1.9 2002/06/12 07:55:58 bv131302
042: * more rebranding - filenames
043: *
044: * Revision 1.8 2002/06/11 16:02:03 bv131302
045: * new branded
046: *
047: * Revision 1.7 2002/06/02 09:50:49 ss133690
048: * CRT 1281 Bug 4618920 Option to make Gateway PDC work with other authentication mechanism (Authentication chain)
049: *
050: * Revision 1.6 2002/05/31 11:41:39 ss133690
051: * CRT 1269 Bug 4618938 Option to disable browser caching
052: *
053: * Revision 1.5 2002/04/05 13:37:32 mm132998
054: * Bug ID : # 4516049 , CRT : # 737 , Desc : Gateway incorrectly handles multiple Content-Length headers
055: *
056: * Revision 1.4 2002/03/20 04:35:24 mm132998
057: * Bug ID # 4655269 CRT : # 602 Desc : Support for HTTP persistent connection at gateway
058: *
059: * Revision 1.3 2002/03/13 13:43:33 mm132998
060: * Gateway log migration to iDSAME , Bug ID : # 4651299 , CRT : # 543
061: *
062: * Revision 1.2 2002/02/26 11:02:08 mm132998
063: * Bug ID : 4643126 CRT : 368 Desc: Lihue PRD 7.4.3
064: *
065: *
066: */
067: /*
068: * HTTPResponse.java
069: *
070: * $Author: ss150821 $
071: *
072: * $Date: 2005/11/30 11:27:21 $ $Revision: 1.12 $
073: *
074: * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
075: *
076: * Developed by SunPS and SunIR
077: */
078:
079: package com.sun.portal.rproxy.connectionhandler;
080:
081: import java.io.BufferedInputStream;
082: import java.io.ByteArrayOutputStream;
083: import java.io.DataOutputStream;
084: import java.io.IOException;
085: import java.util.ArrayList;
086: import java.util.HashMap;
087: import java.util.Iterator;
088: import java.util.LinkedList;
089: import java.util.List;
090: import java.util.Map;
091: import java.util.StringTokenizer;
092:
093: import com.sun.portal.util.ServiceIdentifier;
094: import com.sun.portal.util.SystemProperties;
095:
096: /**
097: * This represents a single response.
098: *
099: * @author Gabriel Lawrence
100: */
101: public class HTTPResponse implements Response {
102: private static final String _crlf = new String(
103: new byte[] { 13, 10 });
104:
105: private static final String _lf = new String(new byte[] { 10 });
106:
107: private List _headerLines = new ArrayList();
108:
109: private boolean _firstLine = true;
110:
111: private static final String supportedHTTPVersion = "HTTP/1.0";
112:
113: private String _httpVersion = supportedHTTPVersion;
114:
115: private boolean _headerComplete = false;
116:
117: private String _statusCode = null;
118:
119: private String _statusText = null;
120:
121: private String _contentType = null;
122:
123: private String _contentEncoding = null;
124:
125: private BufferedInputStream _contentStream = null;
126:
127: private Map _headerCache = new HashMap();
128:
129: private CachedSocket sock = null;
130:
131: public HTTPResponse() {
132: }
133:
134: public void setSocket(CachedSocket socket) {
135: sock = socket;
136: }
137:
138: public void closeSocket() {
139: if (sock != null) {
140: try {
141: sock.close();
142: } catch (Exception e) {
143: }
144: }
145: }
146:
147: public String getHTTPVersion() {
148: return _httpVersion;
149: }
150:
151: public String getStatusCode() {
152: return _statusCode;
153: }
154:
155: public String getStatusText() {
156: return _statusText;
157: }
158:
159: public String getContentType() {
160: try {
161: if (_contentType == null) {
162: String header = getResponseHeader("Content-Type");
163: int start = header.indexOf(':');
164: if (start == -1) {
165: _contentType = "";
166: } else {
167: if (header.endsWith(_crlf)) {
168: _contentType = header.substring(start + 1,
169: header.length() - 2).trim();
170: } else {
171: _contentType = header.substring(start + 1,
172: header.length() - 1).trim();
173: }
174: }
175: }
176: } catch (NullPointerException ex) {
177: }
178: return _contentType;
179: }
180:
181: public void setContentLength(int length) {
182: String header = getResponseHeader("Content-Length");
183: if (header != null) {
184: int numElements = _headerLines.size();
185: for (int i = 0; i < numElements; ++i) {
186: if (header.equals((String) _headerLines.get(i))) {
187: _headerLines.remove(i);
188: // Bug ID - 4516049
189: numElements = _headerLines.size();
190: // break;
191: // EOC : Bug ID - 4516049
192: }
193: }
194: }
195: _headerLines.add("Content-Length: " + length + "\r\n");
196: }
197:
198: /**
199: * Bug 4618938 When "gateway.allow.client.caching" is set to false in
200: * Platform.conf the client cache will be disabled.
201: */
202: /*
203: * public void setClientCaching() { String shouldICache =
204: * SystemProperties.get("gateway.allow.client.caching"); if (shouldICache ==
205: * null) shouldICache = "true";
206: *
207: * if ((shouldICache.toLowerCase()).equals("false")) {
208: *
209: * String header = getResponseHeader("Pragma"); if (header!=null) { int
210: * numElements = _headerLines.size(); for (int i = 0; i < numElements; ++i) {
211: * if (header.equals((String) _headerLines.get(i))) {
212: * _headerLines.remove(i); break; } } } _headerLines.add("Pragma:
213: * no-cache\r\n"); _headerCache.put("Pragma","Pragma: no-cache"); } }
214: */
215: // End of change of code for the bug 4618938
216: /*
217: * Redoing the method to implement the following logic. If
218: * gateway.allow.client.caching=false add "Pragma: no-cache" else If
219: * gateway.allow.client.caching=true remove "Pragma: no-cache" else (not
220: * defined in platform.conf) do nothing This logic is requested for and
221: * specified in bug id : 4831618
222: */
223: private static final String allowClientCaching = SystemProperties
224: .get("gateway.allow.client.caching");
225:
226: public void setClientCaching() {
227:
228: if (allowClientCaching == null) {
229: // Not specified - so dont tamper with the header.
230: return;
231: }
232:
233: // Strip off whatever pragma header is present.
234: String header = getResponseHeader("Pragma");
235: if (header != null) {
236: removeHeader("Pragma");
237: }
238:
239: if (allowClientCaching.toLowerCase().equals("false")) {
240: _headerLines.add("Pragma: no-cache\r\n");
241: }
242: }
243:
244: // End of Code for 4831618
245:
246: public void setConnectionClose() {
247: String header = getResponseHeader("Connection");
248: if (header != null) {
249: int numElements = _headerLines.size();
250: for (int i = 0; i < numElements; ++i) {
251: if (header.equals((String) _headerLines.get(i))) {
252: _headerLines.remove(i);
253: // Lihue KeepAlive
254: // Clear the entry from Cache also
255: _headerCache.remove("connection");
256: // End of Code : Lihue KeepAlive
257: break;
258: }
259: }
260: }
261: _headerLines.add("Connection: close\r\n");
262: }
263:
264: // Lihue KeepAlive
265: public void setConnectionAlive(String token) {
266:
267: // Remove previous entries for Connection and KeepAlive headers
268: String connHeader = getResponseHeader("Connection");
269: String keepAliveHeader = getResponseHeader("KeepAlive");
270: int numHeaderDone = 0;
271: boolean compareConnHeader = (connHeader != null);
272: boolean compareKeepAliveHeader = (keepAliveHeader != null);
273: int numHeaderToDo = 0;
274:
275: if (compareConnHeader) {
276: numHeaderToDo++;
277: }
278:
279: if (compareKeepAliveHeader) {
280: numHeaderToDo++;
281: }
282:
283: for (Iterator iter = _headerLines.iterator(); iter.hasNext();) {
284: String headerValue = (String) iter.next();
285: if (compareConnHeader
286: && connHeader.equalsIgnoreCase(headerValue)) {
287: iter.remove();
288: _headerCache.remove("connection");
289: }
290:
291: if (compareKeepAliveHeader
292: && keepAliveHeader.equalsIgnoreCase(headerValue)) {
293: iter.remove();
294: _headerCache.remove("keepalive");
295: }
296: }
297: // Set new entries for Connection and KeepAlive headers
298: _headerLines.add("Connection: Keep-Alive\r\n");
299: _headerLines.add("Keep-Alive: " + token + "\r\n");
300: }
301:
302: // End of Code : Lihue KeepAlive
303:
304: public void setLocation(String location) {
305: String header = getResponseHeader("Location");
306: if (header != null) {
307: int numElements = _headerLines.size();
308: for (int i = 0; i < numElements; ++i) {
309: if (header.equals((String) _headerLines.get(i))) {
310: _headerLines.remove(i);
311: break;
312: }
313: }
314: }
315: if ((location.toLowerCase()).startsWith("location:")) {
316: _headerLines.add(location);
317: } else {
318: _headerLines.add("Location: " + location + "\r\n");
319: }
320: }
321:
322: public void setContentLocation(String location) {
323: String header = getResponseHeader("Content-Location");
324: if (header != null) {
325: int numElements = _headerLines.size();
326: for (int i = 0; i < numElements; ++i) {
327: if (header.equals((String) _headerLines.get(i))) {
328: _headerLines.remove(i);
329: break;
330: }
331: }
332: }
333: if ((location.toLowerCase()).startsWith("content-location:")) {
334: _headerLines.add(location);
335: } else {
336: _headerLines.add("Content-Location: " + location + "\r\n");
337: }
338: }
339:
340: public String getContentEncoding() {
341: try {
342: if (_contentEncoding == null) {
343: String header = getResponseHeader("Content-Encoding");
344: int start = header.indexOf(':');
345: if (start == -1) {
346: _contentEncoding = "";
347: } else {
348: _contentEncoding = header.substring(start + 1,
349: header.length() - 2).trim();
350: }
351: }
352: } catch (NullPointerException ex) {
353: }
354: return _contentEncoding;
355: }
356:
357: /**
358: * get an arbitrary header
359: */
360: public String getResponseHeader(String header) {
361: // Lihue PRD : 7.4.3.1
362: // To make the cache comparisons case insensitive
363: header = header.toLowerCase();
364: // End of Code : Lihue PRD : 7.4.3.1
365: String result = (String) _headerCache.get(header);
366:
367: if (result == null) {
368: String s;
369: int numElements = _headerLines.size();
370: for (int i = 0; (i < numElements) && (result == null); ++i) {
371: s = (String) _headerLines.get(i);
372: if (s
373: .regionMatches(true, 0, header, 0, header
374: .length())) {
375: result = s;
376: _headerCache.put(header, s);
377: }
378: }
379: }
380:
381: return result;
382: }
383:
384: /*
385: * PRD 3.7 (4338513) Authentication chaining will work with Certificate
386: * authentication.
387: */
388: public void setResponseHeader(String header, String value) {
389: if (header == null || value == null) {
390: return;
391: }
392:
393: int vallen = value.length();
394: if (value.charAt(vallen - 1) != '\n'
395: || value.charAt(vallen - 2) != '\r') {
396: value = value + _crlf;
397: }
398: String s;
399: int headerLen = header.length();
400: int numHeaders = _headerLines.size();
401: for (int i = 0; i < numHeaders; ++i) {
402: s = (String) _headerLines.get(i);
403: if (s.regionMatches(true, 0, header, 0, headerLen)) {
404: _headerLines.remove(i);
405: _headerLines.add(value);
406: _headerCache.remove(header);
407: return;
408: }
409: }
410: _headerLines.add(value);
411: }
412:
413: // End of code change for PRD 3.7
414:
415: /*
416: * Bug 4711442 problem with PDC auth users relogin with Auth chaining
417: * enabled.
418: */
419: public void appendResponseHeader(String header, String value) {
420: if (header == null || value == null) {
421: return;
422: }
423:
424: int vallen = value.length();
425: if (value.charAt(vallen - 1) != '\n'
426: || value.charAt(vallen - 2) != '\r') {
427: value = value + _crlf;
428: }
429: /*
430: * String s; int headerLen = header.length(); int numHeaders =
431: * _headerLines.size(); for (int i = 0; i < numHeaders; ++i) { s =
432: * (String)_headerLines.get(i); if (s.regionMatches(true, 0, header, 0,
433: * headerLen)) { _headerLines.add(value); _headerCache.remove(header);
434: * return; } }
435: */
436: _headerLines.add(value);
437: }
438:
439: public void removeResponseHeader(String header) {
440: if (header == null)
441: return;
442:
443: String s;
444: int headerLen = header.length();
445: _headerCache.remove(header);
446:
447: Iterator iter = _headerLines.iterator();
448: while (iter.hasNext()) {
449: s = iter.next().toString();
450: if (s.regionMatches(true, 0, header, 0, headerLen)) {
451: iter.remove();
452: }
453: }
454: }
455:
456: // End of code change for the bug 4711442
457:
458: /**
459: * Content stream
460: */
461: public BufferedInputStream getContentStream() {
462: return _contentStream;
463: }
464:
465: public void setContentStream(BufferedInputStream in) {
466: _contentStream = in;
467: }
468:
469: /**
470: * Called by retriever when it builds the response
471: */
472: public boolean isHeaderComplete() {
473: return _headerComplete;
474: }
475:
476: /**
477: * Called by retriever when it builds the response
478: */
479: public void addHeaderLine(String s) {
480: if (_firstLine) {
481: if (!s.equals(_crlf)) {
482: _firstLine = false;
483: StringTokenizer st = new StringTokenizer(s);
484: // Always ignorimg the server's version and setting our version
485: // ...
486: // _httpVersion=st.nextToken();
487: st.nextToken();
488: _httpVersion = supportedHTTPVersion;
489: _statusCode = st.nextToken();
490: if (st.hasMoreTokens()) {
491: _statusText = s.substring(
492: s.indexOf(_statusCode)
493: + _statusCode.length(),
494: s.length() - 2).trim();
495: } else {
496: _statusText = "";
497: }
498: }
499: } else {
500: if (s.equals(_crlf) || s.equals(_lf)) {
501: _headerComplete = true;
502: } else {
503: _headerLines.add(s);
504: }
505: }
506: }
507:
508: public byte[] getHeaderBytes() {
509: ByteArrayOutputStream outBAOS = new ByteArrayOutputStream();
510:
511: try {
512: DataOutputStream out = new DataOutputStream(outBAOS);
513: out.write((getHTTPVersion() + " " + getStatusCode() + " "
514: + getStatusText() + "\r\n").getBytes());
515: String s;
516: int numElems = _headerLines.size();
517: for (int i = 0; i < numElems; ++i) {
518: s = (String) _headerLines.get(i);
519: if (!s.endsWith(_crlf)) {
520: s = s.substring(0, s.indexOf("\n")) + _crlf;
521: }
522: if ((s.toLowerCase()).startsWith("content-disposition")) {
523: out.write(s.getBytes("ISO-8859-1"));
524: } else {
525: out.write(s.getBytes());
526: }
527: }
528: out.write("\r\n".getBytes());
529: out.flush();
530: } catch (IOException ex) {
531: }
532: return outBAOS.toByteArray();
533: }
534:
535: public String toString() {
536: return new String(getHeaderBytes());
537: }
538:
539: public void setStatusText(String st) {
540: _statusText = st;
541: }
542:
543: // Replacing with a better impl below.
544: /*
545: * // iDSAME Logging Migration public List getHeaderAttributeList(String
546: * header){ String s; int headerLength = header.length(); int numElements =
547: * _headerLines.size(); LinkedList list = new LinkedList();
548: *
549: * for (int i = 0; i < numElements; ++i) { s =
550: * _headerLines.get(i).toString(); if (s.regionMatches(true, 0, header, 0,
551: * headerLength)) { list.addLast(s); } } return list; } // EOC : iDSAME
552: * Logging Migration
553: */
554:
555: // Map support.
556: public void processSetCookieHeaders(Request req) {
557:
558: if (!ServiceIdentifier.isGateway() || req.isCookieSupported()) {
559: return;
560: }
561:
562: CookieManager.processSetCookieHeaders(req, this );
563: }
564:
565: // WebDAV Support
566: public List getHeaderAttributeList(String header) {
567: String s;
568: int headerLength = header.length();
569: int numElements = _headerLines.size();
570: LinkedList list = new LinkedList();
571: String tHeader;
572: int indx;
573:
574: for (int i = 0; i < numElements; ++i) {
575: s = _headerLines.get(i).toString();
576: indx = s.indexOf(':');
577:
578: if (indx == -1) {
579: continue;
580: }
581: tHeader = s.substring(0, indx).trim();
582: // if (s.regionMatches(true, 0, header, 0, headerLength))
583: if (tHeader.equalsIgnoreCase(header)) {
584: list.addLast(s);
585: }
586: }
587: return list;
588: }
589:
590: public boolean removeHeader(String header) {
591: boolean removed = false;
592: String s;
593: int numElements = _headerLines.size();
594: Iterator iter = _headerLines.iterator();
595: header = header.trim().toLowerCase();
596:
597: String tHeader;
598: int indx;
599:
600: while (iter.hasNext()) {
601: s = iter.next().toString();
602: indx = s.indexOf(':');
603: if (indx == -1) {
604: continue;
605: }
606: tHeader = s.substring(0, indx).trim();
607: if (tHeader.equalsIgnoreCase(header)) {
608: iter.remove();
609: removed = true;
610: }
611: }
612: _headerCache.remove(header);
613: return removed;
614: }
615:
616: // IMPORTANT : headerName - NOT expected to have ':' in it
617: public void setHeader(String headerName, String headerValue) {
618: // Is headerderValue prefixed with headerName ?
619: // If not , prefix it now.
620: int dotIndex = headerValue.indexOf(':');
621: boolean needPrefixing = false;
622:
623: if (dotIndex != -1) {
624: String tmpHeaderName = headerValue.substring(0, dotIndex)
625: .trim();
626: if (!tmpHeaderName.equalsIgnoreCase(headerName)) {
627: needPrefixing = true;
628: }
629: } else {
630: needPrefixing = true;
631: }
632:
633: if (needPrefixing) {
634: headerValue = headerName + " : " + headerValue;
635: }
636: _headerLines.add(headerValue);
637: }
638:
639: // IMPORTANT : headerName - NOT expected to have ':' in it
640: public void setHeader(String headerName, List headers) {
641: Iterator iter = headers.iterator();
642:
643: while (iter.hasNext()) {
644: this.setHeader(headerName, iter.next().toString());
645: }
646: }
647: }
|