001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.net;
019:
020: import java.io.IOException;
021:
022: import org.apache.harmony.luni.util.Msg;
023:
024: /**
025: * This abstract subclass of <code>URLConnection</code> defines method for
026: * managing HTTP connection according to the description given by RFC 2068
027: *
028: * @see ContentHandler
029: * @see URL
030: * @see URLConnection
031: * @see URLStreamHandler
032: */
033: public abstract class HttpURLConnection extends URLConnection {
034: @SuppressWarnings("nls")
035: private String methodTokens[] = { "GET", "DELETE", "HEAD",
036: "OPTIONS", "POST", "PUT", "TRACE" };
037:
038: // Request method, DEFAULT: "GET"
039: protected String method = "GET"; //$NON-NLS-1$
040:
041: // Response code obtained from the request
042: protected int responseCode = -1;
043:
044: // Response message, corresponds to the response code
045: protected String responseMessage;
046:
047: protected boolean instanceFollowRedirects = followRedirects;
048:
049: private static boolean followRedirects = true;
050:
051: protected int chunkLength = -1;
052:
053: protected int fixedContentLength = -1;
054:
055: private final static int DEFAULT_CHUNK_LENGTH = 1024;
056:
057: // 2XX: generally "OK"
058: // 3XX: relocation/redirect
059: // 4XX: client error
060: // 5XX: server error
061: /**
062: * Numeric status code, 202: Accepted
063: */
064: public final static int HTTP_ACCEPTED = 202;
065:
066: /**
067: * Numeric status code, 502: Bad Gateway
068: */
069: public final static int HTTP_BAD_GATEWAY = 502;
070:
071: /**
072: * Numeric status code, 405: Bad Method
073: */
074: public final static int HTTP_BAD_METHOD = 405;
075:
076: /**
077: * Numeric status code, 400: Bad Request
078: */
079: public final static int HTTP_BAD_REQUEST = 400;
080:
081: /**
082: * Numeric status code, 408: Client Timeout
083: */
084: public final static int HTTP_CLIENT_TIMEOUT = 408;
085:
086: /**
087: * Numeric status code, 409: Conflict
088: */
089: public final static int HTTP_CONFLICT = 409;
090:
091: /**
092: * Numeric status code, 201: Created
093: */
094: public final static int HTTP_CREATED = 201;
095:
096: /**
097: * Numeric status code, 413: Entity too large
098: */
099: public final static int HTTP_ENTITY_TOO_LARGE = 413;
100:
101: /**
102: * Numeric status code, 403: Forbidden
103: */
104: public final static int HTTP_FORBIDDEN = 403;
105:
106: /**
107: * Numeric status code, 504: Gateway timeout
108: */
109: public final static int HTTP_GATEWAY_TIMEOUT = 504;
110:
111: /**
112: * Numeric status code, 410: Gone
113: */
114: public final static int HTTP_GONE = 410;
115:
116: /**
117: * Numeric status code, 500: Internal error
118: */
119: public final static int HTTP_INTERNAL_ERROR = 500;
120:
121: /**
122: * Numeric status code, 411: Length required
123: */
124: public final static int HTTP_LENGTH_REQUIRED = 411;
125:
126: /**
127: * Numeric status code, 301 Moved permanently
128: */
129: public final static int HTTP_MOVED_PERM = 301;
130:
131: /**
132: * Numeric status code, 302: Moved temporarily
133: */
134: public final static int HTTP_MOVED_TEMP = 302;
135:
136: /**
137: * Numeric status code, 300: Multiple choices
138: */
139: public final static int HTTP_MULT_CHOICE = 300;
140:
141: /**
142: * Numeric status code, 204: No content
143: */
144: public final static int HTTP_NO_CONTENT = 204;
145:
146: /**
147: * Numeric status code, 406: Not acceptable
148: */
149: public final static int HTTP_NOT_ACCEPTABLE = 406;
150:
151: /**
152: * Numeric status code, 203: Not authoritative
153: */
154: public final static int HTTP_NOT_AUTHORITATIVE = 203;
155:
156: /**
157: * Numeric status code, 404: Not found
158: */
159: public final static int HTTP_NOT_FOUND = 404;
160:
161: /**
162: * Numeric status code, 501: Not implemented
163: */
164: public final static int HTTP_NOT_IMPLEMENTED = 501;
165:
166: /**
167: * Numeric status code, 304: Not modified
168: */
169: public final static int HTTP_NOT_MODIFIED = 304;
170:
171: /**
172: * Numeric status code, 200: OK
173: */
174: public final static int HTTP_OK = 200;
175:
176: /**
177: * Numeric status code, 206: Partial
178: */
179: public final static int HTTP_PARTIAL = 206;
180:
181: /**
182: * Numeric status code, 402: Payment required
183: */
184: public final static int HTTP_PAYMENT_REQUIRED = 402;
185:
186: /**
187: * Numeric status code, 412: Precondition failed
188: */
189: public final static int HTTP_PRECON_FAILED = 412;
190:
191: /**
192: * Numeric status code, 407: Proxy authentication required
193: */
194: public final static int HTTP_PROXY_AUTH = 407;
195:
196: /**
197: * Numeric status code, 414: Request too long
198: */
199: public final static int HTTP_REQ_TOO_LONG = 414;
200:
201: /**
202: * Numeric status code, 205: Reset
203: */
204: public final static int HTTP_RESET = 205;
205:
206: /**
207: * Numeric status code, 303: See other
208: */
209: public final static int HTTP_SEE_OTHER = 303;
210:
211: /**
212: * @deprecated Use HTTP_INTERNAL_ERROR
213: */
214: @Deprecated
215: public final static int HTTP_SERVER_ERROR = 500;
216:
217: /**
218: * Numeric status code, 305: Use proxy
219: */
220: public final static int HTTP_USE_PROXY = 305;
221:
222: /**
223: * Numeric status code, 401: Unauthorized
224: */
225: public final static int HTTP_UNAUTHORIZED = 401;
226:
227: /**
228: * Numeric status code, 415: Unsupported type
229: */
230: public final static int HTTP_UNSUPPORTED_TYPE = 415;
231:
232: /**
233: * Numeric status code, 503: Unavailable
234: */
235: public final static int HTTP_UNAVAILABLE = 503;
236:
237: /**
238: * Numeric status code, 505: Version not supported
239: */
240: public final static int HTTP_VERSION = 505;
241:
242: /**
243: * Constructs a <code>HttpURLConnection</code> pointing to the resource
244: * specified by the <code>URL</code>.
245: *
246: * @param url
247: * the URL of this connection
248: *
249: * @see URL
250: * @see URLConnection
251: */
252: protected HttpURLConnection(URL url) {
253: super (url);
254: }
255:
256: /**
257: * Closes the connection with the HTTP server
258: *
259: * @see URLConnection#connect()
260: * @see URLConnection#connected
261: */
262: public abstract void disconnect();
263:
264: /**
265: * Answers a input stream from the server in the case of error such as the
266: * requested file (txt, htm, html) is not found on the remote server.
267: * <p>
268: * If the content type is not what stated above,
269: * <code>FileNotFoundException</code> is thrown.
270: *
271: * @return the error input stream returned by the server.
272: */
273: public java.io.InputStream getErrorStream() {
274: return null;
275: }
276:
277: /**
278: * Answers the value of <code>followRedirects</code> which indicates if
279: * this connection will follows a different URL redirected by the server. It
280: * is enabled by default.
281: *
282: * @return The value of the flag
283: *
284: * @see #setFollowRedirects
285: */
286: public static boolean getFollowRedirects() {
287: return followRedirects;
288: }
289:
290: /**
291: * Answers the permission object (in this case, SocketPermission) with the
292: * host and the port number as the target name and "resolve, connect" as the
293: * action list.
294: *
295: * @return the permission object required for this connection
296: *
297: * @throws IOException
298: * if an IO exception occurs during the creation of the
299: * permission object.
300: */
301: @Override
302: public java.security.Permission getPermission() throws IOException {
303: int port = url.getPort();
304: if (port < 0) {
305: port = 80;
306: }
307: return new SocketPermission(url.getHost() + ":" + port, //$NON-NLS-1$
308: "connect, resolve"); //$NON-NLS-1$
309: }
310:
311: /**
312: * Answers the request method which will be used to make the request to the
313: * remote HTTP server. All possible methods of this HTTP implementation is
314: * listed in the class definition.
315: *
316: * @return the request method string
317: *
318: * @see #method
319: * @see #setRequestMethod
320: */
321: public String getRequestMethod() {
322: return method;
323: }
324:
325: /**
326: * Answers the response code returned by the remote HTTP server
327: *
328: * @return the response code, -1 if no valid response code
329: *
330: * @throws IOException
331: * if there is an IO error during the retrieval.
332: *
333: * @see #getResponseMessage
334: */
335: public int getResponseCode() throws IOException {
336: // Call getInputStream() first since getHeaderField() doesn't return
337: // exceptions
338: getInputStream();
339: String response = getHeaderField(0);
340: if (response == null) {
341: return -1;
342: }
343: response = response.trim();
344: int mark = response.indexOf(" ") + 1; //$NON-NLS-1$
345: if (mark == 0) {
346: return -1;
347: }
348: int last = mark + 3;
349: if (last > response.length()) {
350: last = response.length();
351: }
352: responseCode = Integer.parseInt(response.substring(mark, last));
353: if (last + 1 <= response.length()) {
354: responseMessage = response.substring(last + 1);
355: }
356: return responseCode;
357: }
358:
359: /**
360: * Answers the response message returned the remote HTTP server
361: *
362: * @return the response message. <code>null</code> if such response exists
363: *
364: * @throws IOException
365: * if there is an IO error during the retrieval.
366: *
367: * @see #getResponseCode()
368: * @see IOException
369: */
370: public String getResponseMessage() throws IOException {
371: if (responseMessage != null) {
372: return responseMessage;
373: }
374: getResponseCode();
375: return responseMessage;
376: }
377:
378: /**
379: * Sets the flag of whether this connection will follow redirects returned
380: * by the remote server. This method can only be called with the permission
381: * from the security manager
382: *
383: * @param auto
384: * The value to set
385: *
386: * @see java.lang.SecurityManager#checkSetFactory()
387: */
388: public static void setFollowRedirects(boolean auto) {
389: SecurityManager security = System.getSecurityManager();
390: if (security != null) {
391: security.checkSetFactory();
392: }
393: followRedirects = auto;
394: }
395:
396: /**
397: * Sets the request command which will be sent to the remote HTTP server.
398: * This method can only be called before the connection is made.
399: *
400: * @param method
401: * The <code>non-null</code> string representing the method
402: *
403: * @throws ProtocolException
404: * Thrown when this is called after connected, or the method is
405: * not supported by this HTTP implementation.
406: *
407: * @see #getRequestMethod()
408: * @see #method
409: */
410: public void setRequestMethod(String method)
411: throws ProtocolException {
412: if (connected) {
413: throw new ProtocolException(Msg.getString("K0037")); //$NON-NLS-1$
414: }
415: for (int i = 0; i < methodTokens.length; i++) {
416: if (methodTokens[i].equals(method)) {
417: // if there is a supported method that matches the desired
418: // method, then set the current method and return
419: this .method = methodTokens[i];
420: return;
421: }
422: }
423: // if none matches, then throw ProtocolException
424: throw new ProtocolException();
425: }
426:
427: /**
428: * Answers if this connection uses proxy.
429: *
430: * @return true if this connection supports proxy, false otherwise.
431: */
432: public abstract boolean usingProxy();
433:
434: /**
435: * Answers if this connection follows redirects.
436: *
437: * @return true if this connection follows redirects, false otherwise.
438: */
439: public boolean getInstanceFollowRedirects() {
440: return instanceFollowRedirects;
441: }
442:
443: /**
444: * Sets if this connection follows redirects.
445: *
446: * @param followRedirects
447: * true if this connection should follows redirects, false
448: * otherwise.
449: */
450: public void setInstanceFollowRedirects(boolean followRedirects) {
451: instanceFollowRedirects = followRedirects;
452: }
453:
454: /**
455: * Answers the date value in the form of milliseconds since epoch
456: * corresponding to the field <code>field</code>. Answers
457: * <code>defaultValue</code> if no such field can be found in the response
458: * header.
459: *
460: * @param field
461: * the field in question
462: * @param defaultValue
463: * the default value if no field is found
464: * @return milliseconds since epoch
465: */
466: @Override
467: public long getHeaderFieldDate(String field, long defaultValue) {
468: return super .getHeaderFieldDate(field, defaultValue);
469: }
470:
471: /**
472: * If length of a HTTP request body is known ahead, sets fixed length to
473: * enable streaming without buffering. Sets after connection will cause an
474: * exception.
475: *
476: * @see <code>setChunkedStreamingMode</code>
477: * @param contentLength
478: * the fixed length of the HTTP request body
479: * @throws IllegalStateException
480: * if already connected or other mode already set
481: * @throws IllegalArgumentException
482: * if contentLength is less than zero
483: */
484: public void setFixedLengthStreamingMode(int contentLength) {
485: if (super .connected) {
486: throw new IllegalStateException(Msg.getString("K0079")); //$NON-NLS-1$
487: }
488: if (0 < chunkLength) {
489: throw new IllegalStateException(Msg.getString("KA003")); //$NON-NLS-1$
490: }
491: if (0 > contentLength) {
492: throw new IllegalArgumentException(Msg.getString("K0051")); //$NON-NLS-1$
493: }
494: this .fixedContentLength = contentLength;
495: }
496:
497: /**
498: * If length of a HTTP request body is NOT known ahead, enable chunked
499: * transfer encoding to enable streaming without buffering. Notice that not
500: * all http servers support this mode. Sets after connection will cause an
501: * exception.
502: *
503: * @see <code>setFixedLengthStreamingMode</code>
504: * @param chunklen
505: * the length of a chunk
506: * @throws IllegalStateException
507: * if already connected or other mode already set
508: */
509: public void setChunkedStreamingMode(int chunklen) {
510: if (super .connected) {
511: throw new IllegalStateException(Msg.getString("K0079")); //$NON-NLS-1$
512: }
513: if (0 <= fixedContentLength) {
514: throw new IllegalStateException(Msg.getString("KA003")); //$NON-NLS-1$
515: }
516: if (0 >= chunklen) {
517: chunkLength = DEFAULT_CHUNK_LENGTH;
518: } else {
519: chunkLength = chunklen;
520: }
521: }
522: }
|