/*
* Copyright (c) 2004 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 3nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose,
* including teaching and use in open-source projects.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book,
* please visit http://www.davidflanagan.com/javaexamples3.
*/
//package je3.nio;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
public class HttpGet {
public static void main(String[] args) {
SocketChannel server = null; // Channel for reading from server
FileOutputStream outputStream = null; // Stream to destination file
WritableByteChannel destination; // Channel to write to it
try { // Exception handling and channel closing code follows this block
// Parse the URL. Note we use the new java.net.URI, not URL here.
URI uri = new URI(args[0]);
// Now query and verify the various parts of the URI
String scheme = uri.getScheme();
if (scheme == null || !scheme.equals("http"))
throw new IllegalArgumentException("Must use 'http:' protocol");
String hostname = uri.getHost();
int port = uri.getPort();
if (port == -1)
port = 80; // Use default port if none specified
String path = uri.getRawPath();
if (path == null || path.length() == 0)
path = "/";
String query = uri.getRawQuery();
query = (query == null) ? "" : '?' + query;
// Combine the hostname and port into a single address object.
// java.net.SocketAddress and InetSocketAddress are new in Java 1.4
SocketAddress serverAddress = new InetSocketAddress(hostname, port);
// Open a SocketChannel to the server
server = SocketChannel.open(serverAddress);
// Put together the HTTP request we'll send to the server.
String request = "GET " + path + query + " HTTP/1.1\r\n" + // The request
"Host: " + hostname + "\r\n" + // Required in HTTP 1.1
"Connection: close\r\n" + // Don't keep connection open
"User-Agent: " + HttpGet.class.getName() + "\r\n" + "\r\n"; // Blank
// line
// indicates
// end of
// request
// headers
// Now wrap a CharBuffer around that request string
CharBuffer requestChars = CharBuffer.wrap(request);
// Get a Charset object to encode the char buffer into bytes
Charset charset = Charset.forName("ISO-8859-1");
// Use the charset to encode the request into a byte buffer
ByteBuffer requestBytes = charset.encode(requestChars);
// Finally, we can send this HTTP request to the server.
server.write(requestBytes);
// Set up an output channel to send the output to.
if (args.length > 1) { // Use a specified filename
outputStream = new FileOutputStream(args[1]);
destination = outputStream.getChannel();
} else
// Or wrap a channel around standard out
destination = Channels.newChannel(System.out);
// Allocate a 32 Kilobyte byte buffer for reading the response.
// Hopefully we'll get a low-level "direct" buffer
ByteBuffer data = ByteBuffer.allocateDirect(32 * 1024);
// Have we discarded the HTTP response headers yet?
boolean skippedHeaders = false;
// The code sent by the server
int responseCode = -1;
// Now loop, reading data from the server channel and writing it
// to the destination channel until the server indicates that it
// has no more data.
while (server.read(data) != -1) { // Read data, and check for end
data.flip(); // Prepare to extract data from buffer
// All HTTP reponses begin with a set of HTTP headers, which
// we need to discard. The headers end with the string
// "\r\n\r\n", or the bytes 13,10,13,10. If we haven't already
// skipped them then do so now.
if (!skippedHeaders) {
// First, though, read the HTTP response code.
// Assume that we get the complete first line of the
// response when the first read() call returns. Assume also
// that the first 9 bytes are the ASCII characters
// "HTTP/1.1 ", and that the response code is the ASCII
// characters in the following three bytes.
if (responseCode == -1) {
responseCode = 100 * (data.get(9) - '0') + 10 * (data.get(10) - '0') + 1
* (data.get(11) - '0');
// If there was an error, report it and quit
// Note that we do not handle redirect responses.
if (responseCode < 200 || responseCode >= 300) {
System.err.println("HTTP Error: " + responseCode);
System.exit(1);
}
}
// Now skip the rest of the headers.
try {
for (;;) {
if ((data.get() == 13) && (data.get() == 10) && (data.get() == 13)
&& (data.get() == 10)) {
skippedHeaders = true;
break;
}
}
} catch (BufferUnderflowException e) {
// If we arrive here, it means we reached the end of
// the buffer and didn't find the end of the headers.
// There is a chance that the last 1, 2, or 3 bytes in
// the buffer were the beginning of the \r\n\r\n
// sequence, so back up a bit.
data.position(data.position() - 3);
// Now discard the headers we have read
data.compact();
// And go read more data from the server.
continue;
}
}
// Write the data out; drain the buffer fully.
while (data.hasRemaining())
destination.write(data);
// Now that the buffer is drained, put it into fill mode
// in preparation for reading more data into it.
data.clear(); // data.compact() also works here
}
} catch (Exception e) { // Report any errors that arise
System.err.println(e);
System.err.println("Usage: java HttpGet []");
} finally { // Close the channels and output file stream, if needed
try {
if (server != null && server.isOpen())
server.close();
if (outputStream != null)
outputStream.close();
} catch (IOException e) {
}
}
}
}