- ProxyInfo pi = Platform.detectProxy();
- if (sock == null && pi != null && pi.proxyAutoConfigFunction != null) sock = attemptPAC(pi.proxyAutoConfigFunction);
- if (sock == null && pi != null && ssl && pi.httpsProxyHost != null) sock = attemptHttpProxy(pi.httpsProxyHost, pi.httpsProxyPort);
- if (sock == null && pi != null && pi.httpProxyHost != null) sock = attemptHttpProxy(pi.httpProxyHost, pi.httpProxyPort);
- if (sock == null && pi != null && pi.socksProxyHost != null) sock = attemptSocksProxy(pi.socksProxyHost, pi.socksProxyPort);
- if (sock == null) sock = attemptDirect();
- if (sock == null) throw new HTTPException("all socket creation attempts have failed");
- sock.setTcpNoDelay(true);
+ // Public Methods ////////////////////////////////////////////////////////////////////////////////////////
+
+ public HTTP(String url) { this(url, false); }
+ public HTTP(String url, boolean skipResolveCheck) {
+ originalUrl = url;
+ this.skipResolveCheck = skipResolveCheck;
+ }
+
+ /** Performs an HTTP GET request */
+ public HTTPInputStream GET() throws IOException { return makeRequest(null, null); }
+
+ /** Performs an HTTP POST request; content is appended to the headers (so it should include a blank line to delimit the beginning of the body) */
+ public HTTPInputStream POST(String contentType, String content) throws IOException { return makeRequest(contentType, content); }
+
+ /**
+ * This method isn't synchronized; however, only one thread can be in the inner synchronized block at a time, and the rest of
+ * the method is protected by in-order one-at-a-time semaphore lock-steps
+ */
+ private HTTPInputStream makeRequest(String contentType, String content) throws IOException {
+
+ // Step 1: send the request and establish a semaphore to stop any requests that pipeline after us
+ Semaphore blockOn = null;
+ Semaphore releaseMe = null;
+ synchronized(this) {
+ if (invalid) throw new HTTPException("connection failed on a previous pipelined call");
+ try {
+ connect();
+ sendRequest(contentType, content);
+ } catch (IOException e) {
+ invalid = true;
+ throw e;
+ }
+ blockOn = okToRecieve;
+ releaseMe = okToRecieve = new Semaphore();
+ }
+
+ // Step 2: wait for requests ahead of us to complete, then read the reply off the stream
+ boolean doRelease = true;
+ try {
+ if (blockOn != null) blockOn.block();
+ if (invalid) throw new HTTPException("connection failed on a previous pipelined call");
+
+ Hashtable h = in == null ? null : parseHeaders(in);
+ if (h == null) {
+ // sometimes the server chooses to close the stream between requests
+ in = null; sock = null;
+ releaseMe.release();
+ return makeRequest(contentType, content);
+ }
+
+ String reply = h.get("STATUSLINE").toString();
+
+ if (reply.startsWith("407") || reply.startsWith("401")) {
+
+ if (reply.startsWith("407")) doProxyAuth(h, content == null ? "GET" : "POST");
+ else doWebAuth(h, content == null ? "GET" : "POST");
+
+ if (h.get("HTTP").equals("1.0") && h.get("content-length") == null) {
+ if (Log.on) Log.log(this, "proxy returned an HTTP/1.0 reply with no content-length...");
+ in = null; sock = null;
+ } else {
+ int cl = h.get("content-length") == null ? -1 : Integer.parseInt(h.get("content-length").toString());
+ new HTTPInputStream(in, cl, releaseMe).close();
+ }
+ releaseMe.release();
+ return makeRequest(contentType, content);
+
+ } else if (reply.startsWith("2")) {
+ if (h.get("HTTP").equals("1.0") && h.get("content-length") == null)
+ throw new HTTPException("XWT does not support HTTP/1.0 servers which fail to return the Content-Length header");
+ int cl = h.get("content-length") == null ? -1 : Integer.parseInt(h.get("content-length").toString());
+ HTTPInputStream ret = new HTTPInputStream(in, cl, releaseMe);
+ doRelease = false;
+ return ret;
+
+ } else {
+ throw new HTTPException("HTTP Error: " + reply);
+
+ }
+
+ } catch (IOException e) { invalid = true; throw e;
+ } finally { if (doRelease) releaseMe.release();
+ }