1. /*
  2. * @(#)HttpURLConnection.java 1.36 03/01/23
  3. *
  4. * Copyright 2003 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. * Returns the key for the <code>n</code><sup>th</sup> header field.
  38. * Some implementations may treat the <code>0</code><sup>th</sup>
  39. * header field as special, i.e. as the status line returned by the HTTP
  40. * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status
  41. * line, but <code>getHeaderFieldKey(0)</code> returns null.
  42. *
  43. * @param n an index, where n >=0.
  44. * @return the key for the <code>n</code><sup>th</sup> header field,
  45. * or <code>null</code> if the key does not exist.
  46. */
  47. public String getHeaderFieldKey (int n) {
  48. return null;
  49. }
  50. /**
  51. * Returns the value for the <code>n</code><sup>th</sup> header field.
  52. * Some implementations may treat the <code>0</code><sup>th</sup>
  53. * header field as special, i.e. as the status line returned by the HTTP
  54. * server.
  55. * <p>
  56. * This method can be used in conjunction with the
  57. * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all
  58. * the headers in the message.
  59. *
  60. * @param n an index, where n>=0.
  61. * @return the value of the <code>n</code><sup>th</sup> header field,
  62. * or <code>null</code> if the value does not exist.
  63. * @see java.net.HttpURLConnection#getHeaderFieldKey(int)
  64. */
  65. public String getHeaderField(int n) {
  66. return null;
  67. }
  68. /**
  69. * An <code>int</code> representing the three digit HTTP Status-Code.
  70. * <ul>
  71. * <li> 1xx: Informational
  72. * <li> 2xx: Success
  73. * <li> 3xx: Redirection
  74. * <li> 4xx: Client Error
  75. * <li> 5xx: Server Error
  76. * </ul>
  77. */
  78. protected int responseCode = -1;
  79. /**
  80. * The HTTP response message.
  81. */
  82. protected String responseMessage = null;
  83. /* static variables */
  84. /* do we automatically follow redirects? The default is true. */
  85. private static boolean followRedirects = true;
  86. /**
  87. * If <code>true</code>, the protocol will automatically follow redirects.
  88. * If <code>false</code>, the protocol will not automatically follow
  89. * redirects.
  90. * <p>
  91. * This field is set by the <code>setInstanceFollowRedirects</code>
  92. * method. Its value is returned by the <code>getInstanceFollowRedirects</code>
  93. * method.
  94. * <p>
  95. * Its default value is based on the value of the static followRedirects
  96. * at HttpURLConnection construction time.
  97. *
  98. * @see java.net.HttpURLConnection#setInstanceFollowRedirects(boolean)
  99. * @see java.net.HttpURLConnection#getInstanceFollowRedirects()
  100. * @see java.net.HttpURLConnection#setFollowRedirects(boolean)
  101. */
  102. protected boolean instanceFollowRedirects = followRedirects;
  103. /* valid HTTP methods */
  104. private static final String[] methods = {
  105. "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
  106. };
  107. /**
  108. * Constructor for the HttpURLConnection.
  109. * @param u the URL
  110. */
  111. protected HttpURLConnection (URL u) {
  112. super(u);
  113. }
  114. /**
  115. * Sets whether HTTP redirects (requests with response code 3xx) should
  116. * be automatically followed by this class. True by default. Applets
  117. * cannot change this variable.
  118. * <p>
  119. * If there is a security manager, this method first calls
  120. * the security manager's <code>checkSetFactory</code> method
  121. * to ensure the operation is allowed.
  122. * This could result in a SecurityException.
  123. *
  124. * @param set a <code>boolean</code> indicating whether or not
  125. * to follow HTTP redirects.
  126. * @exception SecurityException if a security manager exists and its
  127. * <code>checkSetFactory</code> method doesn't
  128. * allow the operation.
  129. * @see SecurityManager#checkSetFactory
  130. * @see #getFollowRedirects()
  131. */
  132. public static void setFollowRedirects(boolean set) {
  133. SecurityManager sec = System.getSecurityManager();
  134. if (sec != null) {
  135. // seems to be the best check here...
  136. sec.checkSetFactory();
  137. }
  138. followRedirects = set;
  139. }
  140. /**
  141. * Returns a <code>boolean</code> indicating
  142. * whether or not HTTP redirects (3xx) should
  143. * be automatically followed.
  144. *
  145. * @return <code>true</code> if HTTP redirects should
  146. * be automatically followed, <tt>false</tt> if not.
  147. * @see #setFollowRedirects(boolean)
  148. */
  149. public static boolean getFollowRedirects() {
  150. return followRedirects;
  151. }
  152. /**
  153. * Sets whether HTTP redirects (requests with response code 3xx) should
  154. * be automatically followed by this <code>HttpURLConnection</code>
  155. * instance.
  156. * <p>
  157. * The default value comes from followRedirects, which defaults to
  158. * true.
  159. *
  160. * @param followRedirects a <code>boolean</code> indicating
  161. * whether or not to follow HTTP redirects.
  162. *
  163. * @see java.net.HttpURLConnection#instanceFollowRedirects
  164. * @see #getInstanceFollowRedirects
  165. */
  166. public void setInstanceFollowRedirects(boolean followRedirects) {
  167. instanceFollowRedirects = followRedirects;
  168. }
  169. /**
  170. * Returns the value of this <code>HttpURLConnection</code>'s
  171. * <code>instanceFollowRedirects</code> field.
  172. *
  173. * @return the value of this <code>HttpURLConnection</code>'s
  174. * <code>instanceFollowRedirects</code> field.
  175. * @see java.net.HttpURLConnection#instanceFollowRedirects
  176. * @see #setInstanceFollowRedirects(boolean)
  177. */
  178. public boolean getInstanceFollowRedirects() {
  179. return instanceFollowRedirects;
  180. }
  181. /**
  182. * Set the method for the URL request, one of:
  183. * <UL>
  184. * <LI>GET
  185. * <LI>POST
  186. * <LI>HEAD
  187. * <LI>OPTIONS
  188. * <LI>PUT
  189. * <LI>DELETE
  190. * <LI>TRACE
  191. * </UL> are legal, subject to protocol restrictions. The default
  192. * method is GET.
  193. *
  194. * @param method the HTTP method
  195. * @exception ProtocolException if the method cannot be reset or if
  196. * the requested method isn't valid for HTTP.
  197. * @see #getRequestMethod()
  198. */
  199. public void setRequestMethod(String method) throws ProtocolException {
  200. if (connected) {
  201. throw new ProtocolException("Can't reset method: already connected");
  202. }
  203. // This restriction will prevent people from using this class to
  204. // experiment w/ new HTTP methods using java. But it should
  205. // be placed for security - the request String could be
  206. // arbitrarily long.
  207. for (int i = 0; i < methods.length; i++) {
  208. if (methods[i].equals(method)) {
  209. this.method = method;
  210. return;
  211. }
  212. }
  213. throw new ProtocolException("Invalid HTTP method: " + method);
  214. }
  215. /**
  216. * Get the request method.
  217. * @return the HTTP request method
  218. * @see #setRequestMethod(java.lang.String)
  219. */
  220. public String getRequestMethod() {
  221. return method;
  222. }
  223. /**
  224. * Gets the status code from an HTTP response message.
  225. * For example, in the case of the following status lines:
  226. * <PRE>
  227. * HTTP/1.0 200 OK
  228. * HTTP/1.0 401 Unauthorized
  229. * </PRE>
  230. * It will return 200 and 401 respectively.
  231. * Returns -1 if no code can be discerned
  232. * from the response (i.e., the response is not valid HTTP).
  233. * @throws IOException if an error occurred connecting to the server.
  234. * @return the HTTP Status-Code, or -1
  235. */
  236. public int getResponseCode() throws IOException {
  237. /*
  238. * We're got the response code already
  239. */
  240. if (responseCode != -1) {
  241. return responseCode;
  242. }
  243. /*
  244. * Ensure that we have connected to the server. Record
  245. * exception as we need to re-throw it if there isn't
  246. * a status line.
  247. */
  248. Exception exc = null;
  249. try {
  250. getInputStream();
  251. } catch (Exception e) {
  252. exc = e;
  253. }
  254. /*
  255. * If we can't a status-line then re-throw any exception
  256. * that getInputStream threw.
  257. */
  258. String statusLine = getHeaderField(0);
  259. if (statusLine == null) {
  260. if (exc != null) {
  261. if (exc instanceof RuntimeException)
  262. throw (RuntimeException)exc;
  263. else
  264. throw (IOException)exc;
  265. }
  266. return -1;
  267. }
  268. /*
  269. * Examine the status-line - should be formatted as per
  270. * section 6.1 of RFC 2616 :-
  271. *
  272. * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase
  273. *
  274. * If status line can't be parsed return -1.
  275. */
  276. if (statusLine.startsWith("HTTP/1.")) {
  277. int codePos = statusLine.indexOf(' ');
  278. if (codePos > 0) {
  279. int phrasePos = statusLine.indexOf(' ', codePos+1);
  280. if (phrasePos > 0 && phrasePos < statusLine.length()) {
  281. responseMessage = statusLine.substring(phrasePos+1);
  282. }
  283. // deviation from RFC 2616 - don't reject status line
  284. // if SP Reason-Phrase is not included.
  285. if (phrasePos < 0)
  286. phrasePos = statusLine.length();
  287. try {
  288. responseCode = Integer.parseInt
  289. (statusLine.substring(codePos+1, phrasePos));
  290. return responseCode;
  291. } catch (NumberFormatException e) { }
  292. }
  293. }
  294. return -1;
  295. }
  296. /**
  297. * Gets the HTTP response message, if any, returned along with the
  298. * response code from a server. From responses like:
  299. * <PRE>
  300. * HTTP/1.0 200 OK
  301. * HTTP/1.0 404 Not Found
  302. * </PRE>
  303. * Extracts the Strings "OK" and "Not Found" respectively.
  304. * Returns null if none could be discerned from the responses
  305. * (the result was not valid HTTP).
  306. * @throws IOException if an error occurred connecting to the server.
  307. * @return the HTTP response message, or <code>null</code>
  308. */
  309. public String getResponseMessage() throws IOException {
  310. getResponseCode();
  311. return responseMessage;
  312. }
  313. public long getHeaderFieldDate(String name, long Default) {
  314. String dateString = getHeaderField(name);
  315. try {
  316. dateString.trim();
  317. if (dateString.indexOf("GMT") == -1) {
  318. dateString = dateString+" GMT";
  319. }
  320. return Date.parse(dateString);
  321. } catch (Exception e) {
  322. }
  323. return Default;
  324. }
  325. /**
  326. * Indicates that other requests to the server
  327. * are unlikely in the near future. Calling disconnect()
  328. * should not imply that this HttpURLConnection
  329. * instance can be reused for other requests.
  330. */
  331. public abstract void disconnect();
  332. /**
  333. * Indicates if the connection is going through a proxy.
  334. * @return a boolean indicating if the connection is
  335. * using a proxy.
  336. */
  337. public abstract boolean usingProxy();
  338. public Permission getPermission() throws IOException {
  339. int port = url.getPort();
  340. port = port < 0 ? 80 : port;
  341. String host = url.getHost() + ":" + port;
  342. Permission permission = new SocketPermission(host, "connect");
  343. return permission;
  344. }
  345. /**
  346. * Returns the error stream if the connection failed
  347. * but the server sent useful data nonetheless. The
  348. * typical example is when an HTTP server responds
  349. * with a 404, which will cause a FileNotFoundException
  350. * to be thrown in connect, but the server sent an HTML
  351. * help page with suggestions as to what to do.
  352. *
  353. * <p>This method will not cause a connection to be initiated. If
  354. * the connection was not connected, or if the server did not have
  355. * an error while connecting or if the server had an error but
  356. * no error data was sent, this method will return null. This is
  357. * the default.
  358. *
  359. * @return an error stream if any, null if there have been no
  360. * errors, the connection is not connected or the server sent no
  361. * useful data.
  362. */
  363. public InputStream getErrorStream() {
  364. return null;
  365. }
  366. /**
  367. * The response codes for HTTP, as of version 1.1.
  368. */
  369. // REMIND: do we want all these??
  370. // Others not here that we do want??
  371. /* 2XX: generally "OK" */
  372. /**
  373. * HTTP Status-Code 200: OK.
  374. */
  375. public static final int HTTP_OK = 200;
  376. /**
  377. * HTTP Status-Code 201: Created.
  378. */
  379. public static final int HTTP_CREATED = 201;
  380. /**
  381. * HTTP Status-Code 202: Accepted.
  382. */
  383. public static final int HTTP_ACCEPTED = 202;
  384. /**
  385. * HTTP Status-Code 203: Non-Authoritative Information.
  386. */
  387. public static final int HTTP_NOT_AUTHORITATIVE = 203;
  388. /**
  389. * HTTP Status-Code 204: No Content.
  390. */
  391. public static final int HTTP_NO_CONTENT = 204;
  392. /**
  393. * HTTP Status-Code 205: Reset Content.
  394. */
  395. public static final int HTTP_RESET = 205;
  396. /**
  397. * HTTP Status-Code 206: Partial Content.
  398. */
  399. public static final int HTTP_PARTIAL = 206;
  400. /* 3XX: relocation/redirect */
  401. /**
  402. * HTTP Status-Code 300: Multiple Choices.
  403. */
  404. public static final int HTTP_MULT_CHOICE = 300;
  405. /**
  406. * HTTP Status-Code 301: Moved Permanently.
  407. */
  408. public static final int HTTP_MOVED_PERM = 301;
  409. /**
  410. * HTTP Status-Code 302: Temporary Redirect.
  411. */
  412. public static final int HTTP_MOVED_TEMP = 302;
  413. /**
  414. * HTTP Status-Code 303: See Other.
  415. */
  416. public static final int HTTP_SEE_OTHER = 303;
  417. /**
  418. * HTTP Status-Code 304: Not Modified.
  419. */
  420. public static final int HTTP_NOT_MODIFIED = 304;
  421. /**
  422. * HTTP Status-Code 305: Use Proxy.
  423. */
  424. public static final int HTTP_USE_PROXY = 305;
  425. /* 4XX: client error */
  426. /**
  427. * HTTP Status-Code 400: Bad Request.
  428. */
  429. public static final int HTTP_BAD_REQUEST = 400;
  430. /**
  431. * HTTP Status-Code 401: Unauthorized.
  432. */
  433. public static final int HTTP_UNAUTHORIZED = 401;
  434. /**
  435. * HTTP Status-Code 402: Payment Required.
  436. */
  437. public static final int HTTP_PAYMENT_REQUIRED = 402;
  438. /**
  439. * HTTP Status-Code 403: Forbidden.
  440. */
  441. public static final int HTTP_FORBIDDEN = 403;
  442. /**
  443. * HTTP Status-Code 404: Not Found.
  444. */
  445. public static final int HTTP_NOT_FOUND = 404;
  446. /**
  447. * HTTP Status-Code 405: Method Not Allowed.
  448. */
  449. public static final int HTTP_BAD_METHOD = 405;
  450. /**
  451. * HTTP Status-Code 406: Not Acceptable.
  452. */
  453. public static final int HTTP_NOT_ACCEPTABLE = 406;
  454. /**
  455. * HTTP Status-Code 407: Proxy Authentication Required.
  456. */
  457. public static final int HTTP_PROXY_AUTH = 407;
  458. /**
  459. * HTTP Status-Code 408: Request Time-Out.
  460. */
  461. public static final int HTTP_CLIENT_TIMEOUT = 408;
  462. /**
  463. * HTTP Status-Code 409: Conflict.
  464. */
  465. public static final int HTTP_CONFLICT = 409;
  466. /**
  467. * HTTP Status-Code 410: Gone.
  468. */
  469. public static final int HTTP_GONE = 410;
  470. /**
  471. * HTTP Status-Code 411: Length Required.
  472. */
  473. public static final int HTTP_LENGTH_REQUIRED = 411;
  474. /**
  475. * HTTP Status-Code 412: Precondition Failed.
  476. */
  477. public static final int HTTP_PRECON_FAILED = 412;
  478. /**
  479. * HTTP Status-Code 413: Request Entity Too Large.
  480. */
  481. public static final int HTTP_ENTITY_TOO_LARGE = 413;
  482. /**
  483. * HTTP Status-Code 414: Request-URI Too Large.
  484. */
  485. public static final int HTTP_REQ_TOO_LONG = 414;
  486. /**
  487. * HTTP Status-Code 415: Unsupported Media Type.
  488. */
  489. public static final int HTTP_UNSUPPORTED_TYPE = 415;
  490. /* 5XX: server error */
  491. /**
  492. * HTTP Status-Code 500: Internal Server Error.
  493. * @deprecated it is misplaced and shouldn't have existed.
  494. */
  495. public static final int HTTP_SERVER_ERROR = 500;
  496. /**
  497. * HTTP Status-Code 500: Internal Server Error.
  498. */
  499. public static final int HTTP_INTERNAL_ERROR = 500;
  500. /**
  501. * HTTP Status-Code 501: Not Implemented.
  502. */
  503. public static final int HTTP_NOT_IMPLEMENTED = 501;
  504. /**
  505. * HTTP Status-Code 502: Bad Gateway.
  506. */
  507. public static final int HTTP_BAD_GATEWAY = 502;
  508. /**
  509. * HTTP Status-Code 503: Service Unavailable.
  510. */
  511. public static final int HTTP_UNAVAILABLE = 503;
  512. /**
  513. * HTTP Status-Code 504: Gateway Timeout.
  514. */
  515. public static final int HTTP_GATEWAY_TIMEOUT = 504;
  516. /**
  517. * HTTP Status-Code 505: HTTP Version Not Supported.
  518. */
  519. public static final int HTTP_VERSION = 505;
  520. }