001: // PostableFrame.java
002: // $Id: PostableFrame.java,v 1.7 2002/07/03 16:04:03 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1996.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.jigsaw.frames;
007:
008: import java.io.IOException;
009: import java.io.InputStream;
010: import java.io.StringBufferInputStream;
011: import java.util.Enumeration;
012: import org.w3c.tools.resources.Attribute;
013: import org.w3c.tools.resources.AttributeRegistry;
014: import org.w3c.tools.resources.BooleanAttribute;
015: import org.w3c.tools.resources.ProtocolException;
016: import org.w3c.tools.resources.ResourceException;
017: import org.w3c.jigsaw.forms.URLDecoder;
018: import org.w3c.jigsaw.forms.URLDecoderException;
019: import org.w3c.www.mime.MimeType;
020: import org.w3c.www.http.HTTP;
021: import org.w3c.www.http.HttpFactory;
022: import org.w3c.www.http.HttpTokenList;
023: import org.w3c.jigsaw.http.Client;
024: import org.w3c.jigsaw.http.ClientException;
025: import org.w3c.jigsaw.http.HTTPException;
026: import org.w3c.jigsaw.http.Reply;
027: import org.w3c.jigsaw.http.Request;
028:
029: import org.w3c.jigsaw.html.HtmlGenerator;
030:
031: /**
032: * Handle POST.
033: */
034: public class PostableFrame extends HTTPFrame {
035:
036: private static MimeType type = MimeType.APPLICATION_X_WWW_FORM_URLENCODED;
037: /**
038: * Attribute index - Should we override form values when multiple ?
039: */
040: protected static int ATTR_OVERIDE = -1;
041: /**
042: * Attribute index - Should we silently convert GET to POST methods ?
043: */
044: protected static int ATTR_CONVERT_GET = -1;
045:
046: static {
047: Attribute a = null;
048: Class cls = null;
049: try {
050: cls = Class.forName("org.w3c.jigsaw.frames.PostableFrame");
051: } catch (Exception ex) {
052: ex.printStackTrace();
053: System.exit(1);
054: }
055: // The override attribute:
056: a = new BooleanAttribute("override", Boolean.FALSE,
057: Attribute.EDITABLE);
058: ATTR_OVERIDE = AttributeRegistry.registerAttribute(cls, a);
059: // The convert get attribute:
060: a = new BooleanAttribute("convert-get", Boolean.TRUE,
061: Attribute.EDITABLE);
062: ATTR_CONVERT_GET = AttributeRegistry.registerAttribute(cls, a);
063: }
064:
065: /**
066: * Get the 'convert GET to POST' flag.
067: */
068:
069: public boolean getConvertGetFlag() {
070: return getBoolean(ATTR_CONVERT_GET, false);
071: }
072:
073: /**
074: * Get the 'override multiple form field value' flag.
075: */
076:
077: public boolean getOverrideFlag() {
078: return getBoolean(ATTR_OVERIDE, true);
079: }
080:
081: /**
082: * get the Allowed methods for this resource
083: * @return an HttpTokenList
084: */
085: protected HttpTokenList getAllow() {
086: if (allowed != null) {
087: return allowed;
088: }
089: int size = 5; // the default HEAD GET OPTIONS POST TRACE
090: if (getPutableFlag()) {
091: size++;
092: }
093: if (getAllowDeleteFlag()) {
094: size++;
095: }
096: String allow_str[] = new String[size];
097: int i = 0;
098: if (getAllowDeleteFlag()) {
099: allow_str[i++] = "DELETE";
100: }
101: allow_str[i++] = "HEAD";
102: allow_str[i++] = "GET";
103: allow_str[i++] = "OPTIONS";
104: allow_str[i++] = "POST";
105: if (getPutableFlag()) {
106: allow_str[i++] = "PUT";
107: }
108: allow_str[i] = "TRACE";
109: allowed = HttpFactory.makeStringList(allow_str);
110: return allowed;
111: }
112:
113: /**
114: * Get this resource body.
115: * If we are allowed to convert GET requests to POST, than we first
116: * check to see if there is some search string in the request, and continue
117: * with normal POST request processing.
118: * <p>If there is no search string, or if we are not allowed to convert
119: * GETs to POSTs, than we just invoke our <code>super</code> method,
120: * which will perform the appropriate job.
121: * @param request The request to handle.
122: * @exception ProtocolException If request couldn't be processed.
123: * @exception ResourceException If the resource got a fatal error.
124: */
125: public Reply get(Request request) throws ProtocolException,
126: ResourceException {
127: // Check if we should handle it (is it a POST disguised in GET ?)
128: if ((!getConvertGetFlag()) || (!request.hasState("query")))
129: return super .get(request);
130: // Get the request entity, and decode it:
131: String query = request.getQueryString();
132: InputStream in = new StringBufferInputStream(query);
133: URLDecoder d = new URLDecoder(in, getOverrideFlag());
134: try {
135: d.parse();
136: } catch (URLDecoderException e) {
137: Reply error = request.makeReply(HTTP.BAD_REQUEST);
138: error
139: .setContent("Invalid request:unable to decode form data.");
140: throw new HTTPException(error);
141: } catch (IOException e) {
142: Reply error = request.makeReply(HTTP.BAD_REQUEST);
143: error
144: .setContent("Invalid request: unable to read form data.");
145: throw new HTTPException(error);
146: }
147: return handle(request, d);
148: }
149:
150: /**
151: * Perform the post method.
152: * @param request The request to handle.
153: * @exception ProtocolException If request couldn't be processed.
154: * @exception ResourceException If the resource got a fatal error.
155: */
156: public Reply post(Request request) throws ProtocolException,
157: ResourceException {
158: boolean mustURLDecode = false;
159: // Check that we are dealing with an application/x-www-form-urlencoded:
160: if (request.hasContentType()) {
161: mustURLDecode = (type.match(request.getContentType()) == MimeType.MATCH_SPECIFIC_SUBTYPE);
162: }
163: // Get and decode the request entity:
164: URLDecoder dec = null;
165: if (mustURLDecode) {
166: try {
167: InputStream in = request.getInputStream();
168: // Notify the client we are willing to continue processing:
169: Client client = request.getClient();
170: // FIXME check expect
171: if (client != null) {
172: client.sendContinue();
173: }
174: dec = new URLDecoder(in, getOverrideFlag());
175: dec.parse();
176: } catch (URLDecoderException e) {
177: Reply error = request.makeReply(HTTP.BAD_REQUEST);
178: error.setContent("Invalid request: unable to decode "
179: + "form data.");
180: throw new HTTPException(error);
181: } catch (IOException ex) {
182: Reply error = request.makeReply(HTTP.BAD_REQUEST);
183: error
184: .setContent("Invalid request: unable to read form data.");
185: throw new ClientException(request.getClient(), ex);
186: }
187: }
188: // Handle the stuff:
189: return handle(request, dec);
190: }
191:
192: /**
193: * Handle the form submission, after posted data parsing.
194: * <p>This method ought to be abstract, but for reasonable reason, it
195: * will just dump (parsed) the form content back to the client, so that it
196: * can be used for debugging.
197: * @param request The request proper.
198: * @param data The parsed data content.
199: * @exception ProtocolException If form data processing failed.
200: * @see org.w3c.jigsaw.forms.URLDecoder
201: */
202:
203: public Reply handle(Request request, URLDecoder data)
204: throws ProtocolException {
205: // Now we just dump back the variables we got:
206: HtmlGenerator g = new HtmlGenerator("Form decoded values");
207: if (data != null) {
208: Enumeration e = data.keys();
209: g.append("<p>List of variables and values:</p><ul>");
210: while (e.hasMoreElements()) {
211: String name = (String) e.nextElement();
212: g.append("<li><em>" + name + "</em> = <b>"
213: + data.getValue(name) + "</b></li>");
214: }
215: g.append("</ul>");
216: } else {
217: g
218: .append("<p>Not with the application/x-www-form-urlencoded"
219: + " mime type");
220: }
221: Reply reply = request.makeReply(HTTP.OK);
222: reply.setStream(g);
223: return reply;
224: }
225: }
|