1. /*
  2. * @(#)HttpURLConnection.java 1.42 04/06/07
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.net;
  8. import java.io.InputStream;
  9. import java.io.IOException;
  10. import java.security.Permission;
  11. import java.util.Date;
  12. /**
  13. * A URLConnection with support for HTTP-specific features. See
  14. * <A HREF="http://www.w3.org/pub/WWW/Protocols/"> the spec </A> for
  15. * details.
  16. * <p>
  17. *
  18. * Each HttpURLConnection instance is used to make a single request
  19. * but the underlying network connection to the HTTP server may be
  20. * transparently shared by other instances. Calling the close() methods
  21. * on the InputStream or OutputStream of an HttpURLConnection
  22. * after a request may free network resources associated with this
  23. * instance but has no effect on any shared persistent connection.
  24. * Calling the disconnect() method may close the underlying socket
  25. * if a persistent connection is otherwise idle at that time.
  26. *
  27. * @see java.net.HttpURLConnection#disconnect()
  28. * @since JDK1.1
  29. */
  30. abstract public class HttpURLConnection extends URLConnection {
  31. /* instance variables */
  32. /**
  33. * The HTTP method (GET,POST,PUT,etc.).
  34. */
  35. protected String method = "GET";
  36. /**
  37. * The chunk-length when using chunked encoding streaming mode for output.
  38. * A value of <code>-1</code> means chunked encoding is disabled for output.
  39. */
  40. protected int chunkLength = -1;
  41. /**
  42. * The fixed content-length when using fixed-length streaming mode.
  43. * A value of <code>-1</code> means fixed-length streaming mode is disabled
  44. * for output.
  45. */
  46. protected int fixedContentLength = -1;
  47. /**
  48. * Returns the key for the <code>n</code><sup>th</sup> header field.
  49. * Some implementations may treat the <code>0</code><sup>th</sup>
  50. * header field as special, i.e. as the status line returned by the HTTP
  51. * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status
  52. * line, but <code>getHeaderFieldKey(0)</code> returns null.
  53. *
  54. * @param n an index, where n >=0.
  55. * @return the key for the <code>n</code><sup>th</sup> header field,
  56. * or <code>null</code> if the key does not exist.
  57. */
  58. public String getHeaderFieldKey (int n) {
  59. return null;
  60. }
  61. /**
  62. * This method is used to enable streaming of a HTTP request body
  63. * without internal buffering, when the content length is known in
  64. * advance.
  65. * <p>
  66. * An exception will be thrown if the application
  67. * attempts to write more data than the indicated
  68. * content-length, or if the application closes the OutputStream
  69. * before writing the indicated amount.
  70. * <p>
  71. * When output streaming is enabled, authentication
  72. * and redirection cannot be handled automatically.
  73. * A HttpRetryException will be thrown when reading
  74. * the response if authentication or redirection are required.
  75. * This exception can be queried for the details of the error.
  76. * <p>
  77. * This method must be called before the URLConnection is connected.
  78. *
  79. * @param contentLength The number of bytes which will be written
  80. * to the OutputStream.
  81. *
  82. * @throws IllegalStateException if URLConnection is already connected
  83. * or if a different streaming mode is already enabled.
  84. *
  85. * @throws IllegalArgumentException if a content length less than
  86. * zero is specified.
  87. *
  88. * @see #setChunkedStreamingMode(int)
  89. */
  90. public void setFixedLengthStreamingMode (int contentLength) {
  91. if (connected) {
  92. throw new IllegalStateException ("Already connected");
  93. }
  94. if (chunkLength != -1) {
  95. throw new IllegalStateException ("Chunked encoding streaming mode set");
  96. }
  97. if (contentLength < 0) {
  98. throw new IllegalArgumentException ("invalid content length");
  99. }
  100. fixedContentLength = contentLength;
  101. }
  102. /* Default chunk size (including chunk header) if not specified;
  103. * we want to keep this in sync with the one defined in
  104. * sun.net.www.http.ChunkedOutputStream
  105. */
  106. private static final int DEFAULT_CHUNK_SIZE = 4096;
  107. /**
  108. * This method is used to enable streaming of a HTTP request body
  109. * without internal buffering, when the content length is <b>not</b>
  110. * known in advance. In this mode, chunked transfer encoding
  111. * is used to send the request body. Note, not all HTTP servers
  112. * support this mode.
  113. * <p>
  114. * When output streaming is enabled, authentication
  115. * and redirection cannot be handled automatically.
  116. * A HttpRetryException will be thrown when reading
  117. * the response if authentication or redirection are required.
  118. * This exception can be queried for the details of the error.
  119. * <p>
  120. * This method must be called before the URLConnection is connected.
  121. *
  122. * @param chunklen The number of bytes to write in each chunk.
  123. * If chunklen is less than or equal to zero, a default
  124. * value will be used.
  125. *
  126. * @throws IllegalStateException if URLConnection is already connected
  127. * or if a different streaming mode is already enabled.
  128. *
  129. * @see #setFixedLengthStreamingMode(int)
  130. */
  131. public void setChunkedStreamingMode (int chunklen) {
  132. if (connected) {
  133. throw new IllegalStateException ("Can't set streaming mode: already connected");
  134. }
  135. if (fixedContentLength != -1) {
  136. throw new IllegalStateException ("Fixed length streaming mode set");
  137. }
  138. chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen;
  139. }
  140. /**
  141. * Returns the value for the <code>n</code><sup>th</sup> header field.
  142. * Some implementations may treat the <code>0</code><sup>th</sup>
  143. * header field as special, i.e. as the status line returned by the HTTP
  144. * server.
  145. * <p>
  146. * This method can be used in conjunction with the
  147. * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all
  148. * the headers in the message.
  149. *
  150. * @param n an index, where n>=0.
  151. * @return the value of the <code>n</code><sup>th</sup> header field,
  152. * or <code>null</code> if the value does not exist.
  153. * @see java.net.HttpURLConnection#getHeaderFieldKey(int)
  154. */
  155. public String getHeaderField(int n) {
  156. return null;
  157. }
  158. /**
  159. * An <code>int</code> representing the three digit HTTP Status-Code.
  160. * <ul>
  161. * <li> 1xx: Informational
  162. * <li> 2xx: Success
  163. * <li> 3xx: Redirection
  164. * <li> 4xx: Client Error
  165. * <li> 5xx: Server Error
  166. * </ul>
  167. */
  168. protected int responseCode = -1;
  169. /**
  170. * The HTTP response message.
  171. */
  172. protected String responseMessage = null;
  173. /* static variables */
  174. /* do we automatically follow redirects? The default is true. */
  175. private static boolean followRedirects = true;
  176. /**
  177. * If <code>true</code>, the protocol will automatically follow redirects.
  178. * If <code>false</code>, the protocol will not automatically follow
  179. * redirects.
  180. * <p>
  181. * This field is set by the <code>setInstanceFollowRedirects</code>
  182. * method. Its value is returned by the <code>getInstanceFollowRedirects</code>
  183. * method.
  184. * <p>
  185. * Its default value is based on the value of the static followRedirects
  186. * at HttpURLConnection construction time.
  187. *
  188. * @see java.net.HttpURLConnection#setInstanceFollowRedirects(boolean)
  189. * @see java.net.HttpURLConnection#getInstanceFollowRedirects()
  190. * @see java.net.HttpURLConnection#setFollowRedirects(boolean)
  191. */
  192. protected boolean instanceFollowRedirects = followRedirects;
  193. /* valid HTTP methods */
  194. private static final String[] methods = {
  195. "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
  196. };
  197. /**
  198. * Constructor for the HttpURLConnection.
  199. * @param u the URL
  200. */
  201. protected HttpURLConnection (URL u) {
  202. super(u);
  203. }
  204. /**
  205. * Sets whether HTTP redirects (requests with response code 3xx) should
  206. * be automatically followed by this class. True by default. Applets
  207. * cannot change this variable.
  208. * <p>
  209. * If there is a security manager, this method first calls
  210. * the security manager's <code>checkSetFactory</code> method
  211. * to ensure the operation is allowed.
  212. * This could result in a SecurityException.
  213. *
  214. * @param set a <code>boolean</code> indicating whether or not
  215. * to follow HTTP redirects.
  216. * @exception SecurityException if a security manager exists and its
  217. * <code>checkSetFactory</code> method doesn't
  218. * allow the operation.
  219. * @see SecurityManager#checkSetFactory
  220. * @see #getFollowRedirects()
  221. */
  222. public static void setFollowRedirects(boolean set) {
  223. SecurityManager sec = System.getSecurityManager();
  224. if (sec != null) {
  225. // seems to be the best check here...
  226. sec.checkSetFactory();
  227. }
  228. followRedirects = set;
  229. }
  230. /**
  231. * Returns a <code>boolean</code> indicating
  232. * whether or not HTTP redirects (3xx) should
  233. * be automatically followed.
  234. *
  235. * @return <code>true</code> if HTTP redirects should
  236. * be automatically followed, <tt>false</tt> if not.
  237. * @see #setFollowRedirects(boolean)
  238. */
  239. public static boolean getFollowRedirects() {
  240. return followRedirects;
  241. }
  242. /**
  243. * Sets whether HTTP redirects (requests with response code 3xx) should
  244. * be automatically followed by this <code>HttpURLConnection</code>
  245. * instance.
  246. * <p>
  247. * The default value comes from followRedirects, which defaults to
  248. * true.
  249. *
  250. * @param followRedirects a <code>boolean</code> indicating
  251. * whether or not to follow HTTP redirects.
  252. *
  253. * @see java.net.HttpURLConnection#instanceFollowRedirects
  254. * @see #getInstanceFollowRedirects
  255. */
  256. public void setInstanceFollowRedirects(boolean followRedirects) {
  257. instanceFollowRedirects = followRedirects;
  258. }
  259. /**
  260. * Returns the value of this <code>HttpURLConnection</code>'s
  261. * <code>instanceFollowRedirects</code> field.
  262. *
  263. * @return the value of this <code>HttpURLConnection</code>'s
  264. * <code>instanceFollowRedirects</code> field.
  265. * @see java.net.HttpURLConnection#instanceFollowRedirects
  266. * @see #setInstanceFollowRedirects(boolean)
  267. */
  268. public boolean getInstanceFollowRedirects() {
  269. return instanceFollowRedirects;
  270. }
  271. /**
  272. * Set the method for the URL request, one of:
  273. * <UL>
  274. * <LI>GET
  275. * <LI>POST
  276. * <LI>HEAD
  277. * <LI>OPTIONS
  278. * <LI>PUT
  279. * <LI>DELETE
  280. * <LI>TRACE
  281. * </UL> are legal, subject to protocol restrictions. The default
  282. * method is GET.
  283. *
  284. * @param method the HTTP method
  285. * @exception ProtocolException if the method cannot be reset or if
  286. * the requested method isn't valid for HTTP.
  287. * @see #getRequestMethod()
  288. */
  289. public void setRequestMethod(String method) throws ProtocolException {
  290. if (connected) {
  291. throw new ProtocolException("Can't reset method: already connected");
  292. }
  293. // This restriction will prevent people from using this class to
  294. // experiment w/ new HTTP methods using java. But it should
  295. // be placed for security - the request String could be
  296. // arbitrarily long.
  297. for (int i = 0; i < methods.length; i++) {
  298. if (methods[i].equals(method)) {
  299. this.method = method;
  300. return;
  301. }
  302. }
  303. throw new ProtocolException("Invalid HTTP method: " + method);
  304. }
  305. /**
  306. * Get the request method.
  307. * @return the HTTP request method
  308. * @see #setRequestMethod(java.lang.String)
  309. */
  310. public String getRequestMethod() {
  311. return method;
  312. }
  313. /**
  314. * Gets the status code from an HTTP response message.
  315. * For example, in the case of the following status lines:
  316. * <PRE>
  317. * HTTP/1.0 200 OK
  318. * HTTP/1.0 401 Unauthorized
  319. * </PRE>
  320. * It will return 200 and 401 respectively.
  321. * Returns -1 if no code can be discerned
  322. * from the response (i.e., the response is not valid HTTP).
  323. * @throws IOException if an error occurred connecting to the server.
  324. * @return the HTTP Status-Code, or -1
  325. */
  326. public int getResponseCode() throws IOException {
  327. /*
  328. * We're got the response code already
  329. */
  330. if (responseCode != -1) {
  331. return responseCode;
  332. }
  333. /*
  334. * Ensure that we have connected to the server. Record
  335. * exception as we need to re-throw it if there isn't
  336. * a status line.
  337. */
  338. Exception exc = null;
  339. try {
  340. getInputStream();
  341. } catch (Exception e) {
  342. exc = e;
  343. }
  344. /*
  345. * If we can't a status-line then re-throw any exception
  346. * that getInputStream threw.
  347. */
  348. String statusLine = getHeaderField(0);
  349. if (statusLine == null) {
  350. if (exc != null) {
  351. if (exc instanceof RuntimeException)
  352. throw (RuntimeException)exc;
  353. else
  354. throw (IOException)exc;
  355. }
  356. return -1;
  357. }
  358. /*
  359. * Examine the status-line - should be formatted as per
  360. * section 6.1 of RFC 2616 :-
  361. *
  362. * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase
  363. *
  364. * If status line can't be parsed return -1.
  365. */
  366. if (statusLine.startsWith("HTTP/1.")) {
  367. int codePos = statusLine.indexOf(' ');
  368. if (codePos > 0) {
  369. int phrasePos = statusLine.indexOf(' ', codePos+1);
  370. if (phrasePos > 0 && phrasePos < statusLine.length()) {
  371. responseMessage = statusLine.substring(phrasePos+1);
  372. }
  373. // deviation from RFC 2616 - don't reject status line
  374. // if SP Reason-Phrase is not included.
  375. if (phrasePos < 0)
  376. phrasePos = statusLine.length();
  377. try {
  378. responseCode = Integer.parseInt
  379. (statusLine.substring(codePos+1, phrasePos));
  380. return responseCode;
  381. } catch (NumberFormatException e) { }
  382. }
  383. }
  384. return -1;
  385. }
  386. /**
  387. * Gets the HTTP response message, if any, returned along with the
  388. * response code from a server. From responses like:
  389. * <PRE>
  390. * HTTP/1.0 200 OK
  391. * HTTP/1.0 404 Not Found
  392. * </PRE>
  393. * Extracts the Strings "OK" and "Not Found" respectively.
  394. * Returns null if none could be discerned from the responses
  395. * (the result was not valid HTTP).
  396. * @throws IOException if an error occurred connecting to the server.
  397. * @return the HTTP response message, or <code>null</code>
  398. */
  399. public String getResponseMessage() throws IOException {
  400. getResponseCode();
  401. return responseMessage;
  402. }
  403. public long getHeaderFieldDate(String name, long Default) {
  404. String dateString = getHeaderField(name);
  405. try {
  406. dateString.trim();
  407. if (dateString.indexOf("GMT") == -1) {
  408. dateString = dateString+" GMT";
  409. }
  410. return Date.parse(dateString);
  411. } catch (Exception e) {
  412. }
  413. return Default;
  414. }
  415. /**
  416. * Indicates that other requests to the server
  417. * are unlikely in the near future. Calling disconnect()
  418. * should not imply that this HttpURLConnection
  419. * instance can be reused for other requests.
  420. */
  421. public abstract void disconnect();
  422. /**
  423. * Indicates if the connection is going through a proxy.
  424. * @return a boolean indicating if the connection is
  425. * using a proxy.
  426. */
  427. public abstract boolean usingProxy();
  428. public Permission getPermission() throws IOException {
  429. int port = url.getPort();
  430. port = port < 0 ? 80 : port;
  431. String host = url.getHost() + ":" + port;
  432. Permission permission = new SocketPermission(host, "connect");
  433. return permission;
  434. }
  435. /**
  436. * Returns the error stream if the connection failed
  437. * but the server sent useful data nonetheless. The
  438. * typical example is when an HTTP server responds
  439. * with a 404, which will cause a FileNotFoundException
  440. * to be thrown in connect, but the server sent an HTML
  441. * help page with suggestions as to what to do.
  442. *
  443. * <p>This method will not cause a connection to be initiated. If
  444. * the connection was not connected, or if the server did not have
  445. * an error while connecting or if the server had an error but
  446. * no error data was sent, this method will return null. This is
  447. * the default.
  448. *
  449. * @return an error stream if any, null if there have been no
  450. * errors, the connection is not connected or the server sent no
  451. * useful data.
  452. */
  453. public InputStream getErrorStream() {
  454. return null;
  455. }
  456. /**
  457. * The response codes for HTTP, as of version 1.1.
  458. */
  459. // REMIND: do we want all these??
  460. // Others not here that we do want??
  461. /* 2XX: generally "OK" */
  462. /**
  463. * HTTP Status-Code 200: OK.
  464. */
  465. public static final int HTTP_OK = 200;
  466. /**
  467. * HTTP Status-Code 201: Created.
  468. */
  469. public static final int HTTP_CREATED = 201;
  470. /**
  471. * HTTP Status-Code 202: Accepted.
  472. */
  473. public static final int HTTP_ACCEPTED = 202;
  474. /**
  475. * HTTP Status-Code 203: Non-Authoritative Information.
  476. */
  477. public static final int HTTP_NOT_AUTHORITATIVE = 203;
  478. /**
  479. * HTTP Status-Code 204: No Content.
  480. */
  481. public static final int HTTP_NO_CONTENT = 204;
  482. /**
  483. * HTTP Status-Code 205: Reset Content.
  484. */
  485. public static final int HTTP_RESET = 205;
  486. /**
  487. * HTTP Status-Code 206: Partial Content.
  488. */
  489. public static final int HTTP_PARTIAL = 206;
  490. /* 3XX: relocation/redirect */
  491. /**
  492. * HTTP Status-Code 300: Multiple Choices.
  493. */
  494. public static final int HTTP_MULT_CHOICE = 300;
  495. /**
  496. * HTTP Status-Code 301: Moved Permanently.
  497. */
  498. public static final int HTTP_MOVED_PERM = 301;
  499. /**
  500. * HTTP Status-Code 302: Temporary Redirect.
  501. */
  502. public static final int HTTP_MOVED_TEMP = 302;
  503. /**
  504. * HTTP Status-Code 303: See Other.
  505. */
  506. public static final int HTTP_SEE_OTHER = 303;
  507. /**
  508. * HTTP Status-Code 304: Not Modified.
  509. */
  510. public static final int HTTP_NOT_MODIFIED = 304;
  511. /**
  512. * HTTP Status-Code 305: Use Proxy.
  513. */
  514. public static final int HTTP_USE_PROXY = 305;
  515. /* 4XX: client error */
  516. /**
  517. * HTTP Status-Code 400: Bad Request.
  518. */
  519. public static final int HTTP_BAD_REQUEST = 400;
  520. /**
  521. * HTTP Status-Code 401: Unauthorized.
  522. */
  523. public static final int HTTP_UNAUTHORIZED = 401;
  524. /**
  525. * HTTP Status-Code 402: Payment Required.
  526. */
  527. public static final int HTTP_PAYMENT_REQUIRED = 402;
  528. /**
  529. * HTTP Status-Code 403: Forbidden.
  530. */
  531. public static final int HTTP_FORBIDDEN = 403;
  532. /**
  533. * HTTP Status-Code 404: Not Found.
  534. */
  535. public static final int HTTP_NOT_FOUND = 404;
  536. /**
  537. * HTTP Status-Code 405: Method Not Allowed.
  538. */
  539. public static final int HTTP_BAD_METHOD = 405;
  540. /**
  541. * HTTP Status-Code 406: Not Acceptable.
  542. */
  543. public static final int HTTP_NOT_ACCEPTABLE = 406;
  544. /**
  545. * HTTP Status-Code 407: Proxy Authentication Required.
  546. */
  547. public static final int HTTP_PROXY_AUTH = 407;
  548. /**
  549. * HTTP Status-Code 408: Request Time-Out.
  550. */
  551. public static final int HTTP_CLIENT_TIMEOUT = 408;
  552. /**
  553. * HTTP Status-Code 409: Conflict.
  554. */
  555. public static final int HTTP_CONFLICT = 409;
  556. /**
  557. * HTTP Status-Code 410: Gone.
  558. */
  559. public static final int HTTP_GONE = 410;
  560. /**
  561. * HTTP Status-Code 411: Length Required.
  562. */
  563. public static final int HTTP_LENGTH_REQUIRED = 411;
  564. /**
  565. * HTTP Status-Code 412: Precondition Failed.
  566. */
  567. public static final int HTTP_PRECON_FAILED = 412;
  568. /**
  569. * HTTP Status-Code 413: Request Entity Too Large.
  570. */
  571. public static final int HTTP_ENTITY_TOO_LARGE = 413;
  572. /**
  573. * HTTP Status-Code 414: Request-URI Too Large.
  574. */
  575. public static final int HTTP_REQ_TOO_LONG = 414;
  576. /**
  577. * HTTP Status-Code 415: Unsupported Media Type.
  578. */
  579. public static final int HTTP_UNSUPPORTED_TYPE = 415;
  580. /* 5XX: server error */
  581. /**
  582. * HTTP Status-Code 500: Internal Server Error.
  583. * @deprecated it is misplaced and shouldn't have existed.
  584. */
  585. @Deprecated
  586. public static final int HTTP_SERVER_ERROR = 500;
  587. /**
  588. * HTTP Status-Code 500: Internal Server Error.
  589. */
  590. public static final int HTTP_INTERNAL_ERROR = 500;
  591. /**
  592. * HTTP Status-Code 501: Not Implemented.
  593. */
  594. public static final int HTTP_NOT_IMPLEMENTED = 501;
  595. /**
  596. * HTTP Status-Code 502: Bad Gateway.
  597. */
  598. public static final int HTTP_BAD_GATEWAY = 502;
  599. /**
  600. * HTTP Status-Code 503: Service Unavailable.
  601. */
  602. public static final int HTTP_UNAVAILABLE = 503;
  603. /**
  604. * HTTP Status-Code 504: Gateway Timeout.
  605. */
  606. public static final int HTTP_GATEWAY_TIMEOUT = 504;
  607. /**
  608. * HTTP Status-Code 505: HTTP Version Not Supported.
  609. */
  610. public static final int HTTP_VERSION = 505;
  611. }